找回密码
 注册
关于网站域名变更的通知
查看: 481|回复: 1
打印 上一主题 下一主题

linux学习之路_编写ipcore 的linux driver,然后run helloworld

[复制链接]
  • TA的每日心情

    2019-11-20 15:22
  • 签到天数: 2 天

    [LV.1]初来乍到

    跳转到指定楼层
    1#
    发表于 2021-3-2 17:40 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

    EDA365欢迎您登录!

    您需要 登录 才可以下载或查看,没有帐号?注册

    x
    * Z* z& [" z* h6 S) c
    引言
    7 H6 C& {9 ?! W
    $ \8 m7 [' s+ I: ?" j我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线inteRFace的ip,可以实现plug & work。3 U" d' t( g: {. X- s6 R8 A
      X* Z8 T3 [$ n& @
    所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。
    / G) v  r' U8 |1 R0 J: Q7 Q9 O& O4 x  Q4 }1 ]! q
    本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。
    0 y1 J2 y% q' K* |5 P2 Q* ]( |4 @! r7 M% L7 U

    . w9 l- m* s! F" j5 A8 i" p
    ' y; I! D" a; R$ L6 U" Y! ]11.1 编写wishbone为interface的ip core(ip_mkg)
    1 P7 V% j2 c; x1 z1 ?3 V1 G+ |
    0 M( @( m% g2 _# N, a" z, f6 i1》这一步请参考:
    / X; D8 Y& Q: f  L$ U" D  t( j7 S0 H0 {2 z5 D( [2 F6 f: `
    linux学习之路_wishbone实验
    # i" B* q1 S! K% v; W+ j" v6 |! F# T7 |# Y: x% M
    2》将其中的my_slave_module链接到ORPSoC的wishbone上。% x- n8 T1 f1 K$ t3 ~

    0 Z' t9 D1 ~6 A0 u# `' v3 H
    $ K4 j* C, p+ Y. ]
    ' p3 K: H3 l, b8 z, t. z2 q11.2 编写linux下的driver module+ n& u5 ?2 r% Y8 j8 }. e2 I
    * p1 R3 ^, ]& U; g, L  `
    代码及makefile如下:. p8 R# }, {+ M# O1 p! |
    / K: _$ J! B6 c* x9 p
    1》ip_mkg.c
    9 I, Y8 l: D6 S- q, B0 M7 x5 I7 a
    & s1 @1 |  d! j  Q " q- u4 R8 ~; m' V1 K; w7 l

    + x. v9 F2 t8 j" I) G- G
    • /*
    • *
    • * rill mkg driver
    • *
    • */
    • #include <linux/vmalloc.h>
    • #include <linux/slab.h>
    • #include <linux/kernel.h>
    • #include <linux/module.h>
    • #include <linux/fs.h>
    • #include <asm/uaccess.h> /* get_user and put_user */
    • //#include <linux/clk.h>
    • //#include <linux/ioport.h>
    • #include <asm/io.h> /*ioremap*/
    • #include <linux/platform_device.h> /*cleanup_module*/
    • #include "ip_mkg.h"
    • void        __iomem         *g_mkg_mem_base = NULL;
    • static int device_open(struct inode *inode, struct file *file)
    • {
    •         g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);
    •         if(NULL == g_mkg_mem_base)
    •         {
    •                 printk(KERN_ERR "mkg open ioremap error!\n");
    •                 return -1;
    •         }
    •         else
    •         {
    •                 printk("mkg ioremap addr:%d!\n",(int)g_mkg_mem_base);
    •         }
    •         return 0;
    • }
    • static int device_release(struct inode *inode, struct file *file)
    • {
    •         return 0;
    • }
    • static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
    • {
    •         return 0;
    • }
    • static ssize_t device_write(struct file *filp, const char *buffer, size_t count, loff_t *offset)
    • {
    •    return 0;
    • }
    • long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
    • {
    •    int ret_val = 0;
    •    unsigned int ret = 0;
    •    struct reg_data *new_regs;
    •    switch(ioctl_num)
    •    {
    •       case IOCTL_REG_SET:
    •           {
    •                  new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);
    •                  if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0)
    •                          {
    •                             kfree(new_regs);
    •                             printk(KERN_ERR " error copy line_datafrom user.\n");
    •                                 return -1;
    •                          }
    •                         iowrite16(new_regs->value,g_mkg_mem_base+new_regs->addr);
    •                  kfree(new_regs);
    •      }
    •          break;
    •         case IOCTL_REG_GET:
    •         {
    •          new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);
    •          if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0)
    •                  {
    •                     kfree(new_regs);
    •                     printk(KERN_ERR " error copy line_datafrom user.\n");
    •                         return -1;
    •                  }
    •                 ret = ioread16(g_mkg_mem_base+new_regs->addr);
    •                  kfree(new_regs);
    •                 return ret;
    •         }
    •         break;
    •    }
    •   return -1;
    • }
    • struct file_operations our_file_ops = {
    •   .unlocked_ioctl = device_ioctl,
    •   .read = device_read,
    •   .write = device_write,
    •   .open = device_open,
    •   .release = device_release,
    •   .owner = THIS_MODULE,
    • };
    • int init_module()
    • {
    •         int ret_val;
    •         int ret;
    •         void __iomem *ret_from_request;
    •         //=== Allocate character device
    •         ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &our_file_ops);
    •         if (ret_val < 0)
    •         {
    •                 printk(KERN_ALERT " device %s failed(%d)\n", DEVICE_NAME, ret_val);
    •                 return ret_val;
    •         }
    •         ret = check_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);
    •         if (ret < 0)
    •         {
    •                 printk(KERN_ERR "mkg check_mem_region bussy error!\n");
    •                 return -1;
    •         }
    •         ret_from_request = request_mem_region(MKG_MEM_BASE, MKG_MEM_LEN, "ip_mkg");
    •         //===ioremap mkg registers
    •         g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);
    •         if(NULL == g_mkg_mem_base)
    •         {
    •                 printk(KERN_ERR "mkg ioremap error!\n");
    •                 return -1;
    •         }
    •         else
    •         {
    •                 ;//printk("mkg ioremap addr:%d!\n",g_mkg_mem_base);
    •         }
    •         printk("mkg module init done!\n");
    •         return 0;
    • }
    • void cleanup_module()
    • {
    •         release_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);
    •         unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
    • }
    • MODULE_LICENSE("GPL");
    • MODULE_AUTHOR("Rill zhen:rillzhen@gmail.com");6 T3 D7 _" w. C
                        
    " X2 `5 t; i( d$ V) @) K
    ! X, a5 t" E5 U& B' u5 ~
    & n2 _7 V+ Z% O* [% f1 w2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。) X. z% x4 u, x5 X

    . g/ m- @2 Z0 F) Y, s
    • #ifndef __IP_MKG_H__
    • #define __IP_MKG_H__
    • #define MAJOR_NUM        102
    • #define DEVICE_NAME        "ip_mkg"
    • #define MKG_MEM_BASE 0x10000001
    • #define MKG_MEM_LEN        32
    • #define IOCTL_REG_SET 0
    • #define IOCTL_REG_GET 1
    • struct reg_data
    • {
    •         unsigned short addr;
    •         int value;
    • };
    • #endif
      ) v) r$ }+ y+ N7 A
          
    , l* [" z1 ]- z7 a$ ~/ V
    ! j) j" A) v' B( M' n3 l+ `/ U1 j9 ^- V1 X5 ~8 j' U9 `( E
    3》Makefile! d( m& ]. a( b6 G: K' ]
    # Q0 b9 [4 z* d3 C  R
    • # To build modules outside of the kernel tree, we run "make"
    • # in the kernel source tree; the Makefile these then includes this
    • # Makefile once again.
    • # This conditional selects whether we are being included from the
    • # kernel Makefile or not.
    • ifeq ($(KERNELRELEASE),)
    •     # Assume the source tree is where the running kernel was built
    •     # You should set KERNELDIR in the environment if it's elsewhere
    •     KERNELDIR ?= /home/openrisc/soc-design/linux
    •     # The current directory is passed to sub-makes as argument
    •     PWD := $(shell pwd)
    • modules:
    •         make -C $(KERNELDIR) M=$(PWD) modules ARCH=openrisc CROSS_COMPILE=or32-linux-
    • modules_install:
    •         make -C $(KERNELDIR) M=$(PWD) modules_install ARCH=openrisc CROSS_COMPILE=or32-linux-
    • clean:
    •         rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
    • .PHONY: modules modules_install clean
    • else
    •     # called from kernel build system: just declare what our modules are
    •     obj-m := ip_mkg.o
    • endif# e! P8 ~2 I& x# Y
          $ t& ]$ [3 n6 I; q0 m5 r9 ]1 L4 F
    6 Y6 i5 A, N, X1 U& f

    ; |% _9 q8 |& H5 ?$ z11.3 遇到的问题+ u9 I: H, K8 S6 F
    ; {. U( U! G. [2 o% v9 ?  {- _3 L# K2 \, `
    1》当在执行make时会遇到如下警告:__ioremap undefined。
    5 A3 ^1 K/ I. j$ I2 c: Z" V2 u3 I" L# [& f# i" ]
    7 y9 l9 ~# D( f. o. o* _( ~
    & g3 T& l9 L" C% K) h2 Z
    ( |4 `4 Q, ?. U9 h0 ~$ ?5 Y* ?
    $ G7 @  X) I/ }9 O, I
    2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。
    1 h1 E  {3 F0 u; `' b/ L+ R2 F- L. q

      s8 W/ U+ Y1 T" F" {4 ?3 ^; X* c4 h9 `# o6 {
    7 k2 L# k3 G7 J6 c$ @% o$ h1 }

    * s  C, c1 C0 V" }11.4 解决方法; f# O, h; ^5 l+ l! ^/ P5 w
    " m9 ]7 z# s) X: O- \) |
    在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。8 p, }  b( M" Q# a

    1 i; o- O( e5 \3 k/ e" U4 w: S
    • #include <linux/module.h>
    • EXPORT_SYMBOL(__ioremap);( Z6 V% k7 g: a. U9 D
    6 ?0 J  K- g; F& v% x2 g- V
    - @4 Z& I- @; H' f

    1 d2 C% J- m1 E5 E$ Z  b$ t11.5 小结( \/ \- \( j* K8 H8 d

    ( Y0 i3 C# v4 B* t+ m# o( Y实验步骤
    % g! {/ j6 s. x* k( v2 n" V4 ]* g3 l$ g2 ^
    0》virtualbox虚拟机unbuntu上安装nfs服务, ]. y: ]# q+ ]; Y' m

      W$ d0 q- P: N0.0>确保virtualbox能上网
    0 d, q$ U0 l0 k* ]7 O% e
    & D# {1 o4 h' s& L  k8 K0.1> apt-get install nfs-kernel-server
    ) I9 p5 p, x! B1 e& ]
    1 z/ {" X7 J5 e1 `5 \( V' h0.2>创建nfs共享目录:mkdir /home/openrisc/nfs6 K5 Y; a* `5 _* i0 Q7 W! e, n

    1 s/ I1 [3 ~2 K$ a2 L. I0.3>vim /etc/exports,添加如下内容* o! }( W, T/ C+ L( X! ~

    5 u" p3 v! n, H3 g/home/openrisc/nfs  *(rw,sync)
    ' D8 r2 z1 v# ?3 q0 ~( Y0 m) z4 S$ c9 G5 t! L2 @# z% U
    0.4>重启nfs服务7 Q: j% w) K9 Q  E& p$ P  m

    ; p* m! Z# ]9 ]3 G1 qsudo /etc/init.d/nfs-kernel-server restart
    1 j1 q5 d! \0 |7 u7 Y+ e' b9 P% C; `  a1 m
    1》修改arch/openrisc/mm/ioremap.c
    & G+ _* \  W$ I) o) d, Y0 H7 S: A% |2 x- y* a
    2》cd /home/openrisc/soc-design/linux( u. A2 H3 t/ L' D1 g
    1 V' t9 ^# [8 T5 H" Y# m. U
    3》make ARCH=openrisc defconfig;make生成vmlinux
    : C, U* u% q- ~! H
    ' |! q4 \, {' i2 e% [4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件/ P. f6 J8 s7 X0 d/ h

    ( h6 B* E4 a# J; |6 F* T/ z5》在FPGA板子上运行linux(刚刚生成的vmlinux文件)5 l) `8 q- [1 ^  `! q
    : i3 ~$ j( k6 Q1 k$ O
    6》配置virtualbox的ip
    7 {, m, s8 q8 Z3 T* h  Q$ `% D- e5 T; U8 d
    sudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.255
    . R+ m* _; g+ D- E; \! `0 X& g4 m7 i
    7》配置PC机的ip为192.168.1.1024 v& _" R5 r# {. l

    " k5 }' j9 g" X; ?3 A8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。) E; ]$ l+ ?9 z7 E
    1 a# ]  k8 U1 `# _- I! @, ?# U* W
    9》板子上执行mkdir nfs,创建本地nfs共享目录% h% @5 G9 C' d7 K
    7 f9 [; R* M  F+ v  Q
    10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs
    & \0 Y6 M# I" J5 I3 E* Q' u8 O- g- c9 y+ v1 @
    11》在virtualbox里将ip_mkg.ko copy到nfs共享目录+ a0 O- H6 c2 L- F" K' x7 H

    + ~. F8 w2 E7 t7 y; v$ A% h12》板子上cd nfs- ?' M* Y, v) {& U2 i; ?

    6 c9 m0 S2 e) l; w13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下
    3 l* Q: _( f, f* k. c0 A5 Y% ^" Q( \
    14》创建设备节点:mknod /dev/ip_mkg c 102 0: G" q: ^* V/ L7 w

    6 o2 B% @9 ~5 O$ D  N15》测试:cat /dev/ip_mkg,看到如下结果:0 t' m3 ~) m; u
    1 [' p- }" C/ N% w
    16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下
    8 J4 m  m$ y2 l! e! u7 X0 h' C/ u& G- {; h4 G* V2 t5 y* f) d
    soc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS/ d* r% k6 a; X1 w6 f
    & [6 \1 t( Z4 B+ @
    \soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。 # G( K1 G9 h, m+ s- _

    $ B& y1 ~4 Z- T1 P; S
    / D+ T; _) Y% V- K
    : L* N' @1 c& q" u* N+ u$ U" c' o, W
    9 H7 w0 N. k$ b; P8 }' H/ v/ H; Q+ z
    16》运行helloworld" S0 V( s) I. h. D3 G3 F- i
    ; J5 V4 Q* D. J+ q% H# H$ H
    16.1>编写hello.c4 f# h  o% G  j3 \3 i' h

    8 F& _9 t8 I3 w* t) ^) d4 x5 Z
    • #include <stdio.h>
    • void main()
    • {
    • printf("rill helloworld!\n");
    • }
      8 C" q) ?0 [7 p! L2 X! [3 z4 r

    . ~2 H& U% A5 U. Z
    $ o- n: q2 p; z) [3 q0 T. q+ z
    2 R1 f7 M0 J& Z3 u# e16.2>编译: or2-linux-gcc hello.c -o hello  Q/ l* }5 M; ?  k8 C  z0 h% [
    7 r! G; \( E0 {. _% N; Z. J
    16.3>copy到板子上:cp hello /home/openrisc/nfs
    ( C# q: R2 c9 `( a( l: X* R# O3 B3 S- I6 W% ?
    16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:
    $ l7 j6 K! J! S+ L- n* |: O( H, O- y; O2 O; J8 `8 }& N- g( L

    : y7 u) Q; r3 x( N, i
    ) E0 m( t6 \+ s' p8 @

    该用户从未签到

    2#
    发表于 2021-3-2 18:11 | 只看该作者
    每天学习一个小技巧
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-6-22 14:13 , Processed in 0.093750 second(s), 26 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表