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

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

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

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

    [LV.1]初来乍到

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

    EDA365欢迎您登录!

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

    x
    - [; K% O" @# j9 f4 H/ r; \
    引言' h% \* a! k! h) W+ F1 \
    + j- w4 ~4 C8 R% T
    我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线inteRFace的ip,可以实现plug & work。
    * p+ x; a6 a3 w2 N9 Z8 B% h4 n  s& ~! B" V
    所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。& ~9 `: |" A0 G$ D! B3 z
    8 y; q& r7 }7 x- W5 J
    本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。: p- W: E* h$ D4 Z( A

    # Y( W2 n1 ?1 X, D- h- Y - @& ~& t2 T1 P' a
    # X4 ?1 h! A2 n; Y5 A" p2 X
    11.1 编写wishbone为interface的ip core(ip_mkg), p, V6 |. H4 o3 h( @

    ! |2 `7 {4 Q5 Z* B8 f% q1》这一步请参考:
    ! |+ I; l) r/ V7 e5 |2 t3 {3 s
    9 r3 q7 B! ]& w2 xlinux学习之路_wishbone实验# L; @: r: s, Y2 G
    4 M, |8 H" u4 ~, R$ `8 q
    2》将其中的my_slave_module链接到ORPSoC的wishbone上。, _& I6 ^) N; Y- B

    : a2 |; q+ L$ l0 a6 o6 b ( y; d0 m" h+ x3 R7 C* v
    / z; {5 v7 H1 q7 X
    11.2 编写linux下的driver module9 Z( y2 J$ e% b
    9 H$ J& `3 A0 }" ^1 P
    代码及makefile如下:( \6 ^$ T6 N6 Z/ O# A+ E
    * [( e* z+ k1 x# W
    1》ip_mkg.c
    / J2 B) [- Y5 ^5 l3 s/ m! m0 m; l1 G* C. U/ t4 y$ t! y
    / ?7 B3 m) p. e' q) a

    0 T" {0 [( a1 O( \  W( J3 B! H
    • /*
    • *
    • * 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 A' i2 T1 r& |) G' k6 |1 m$ V* I
                        : ~7 I: [' N. F- n& V

    / d1 T1 Z& A8 _2 z% k2 N3 D& g* H6 A/ a; k
    2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。
    ' `5 ~. X+ _- P- |
    ( K( |, P9 r  Y, _/ h* D8 G% t
    • #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
      % G. A% q* `2 o& W& J" q9 y) V6 O/ x
          9 y& t* i5 q- c$ s9 U

    - H- a, ?; j2 V( K
    8 h# r4 r' V, {: k( d- \3》Makefile
    ! n( Z( q3 c/ H7 ~( ^' `# h
    6 w" C* H$ Y0 P, Y  W2 D# k( a
    • # 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  j; }1 O2 z; u
          
    ( U' p8 S! q; d- i# }: |/ V$ L& v7 b% Z% l6 A) C# ?2 k8 z

      w4 `* e/ u+ b1 K* |11.3 遇到的问题
    2 K- ~& n/ \4 p" e5 R+ h, ~+ |3 }! m) Q6 ~, e  i
    1》当在执行make时会遇到如下警告:__ioremap undefined。
    ( |/ k% X8 n6 f) ]3 M
    - t" g0 \! |! H/ v7 k5 M 8 y! M3 O5 \( A7 @# P$ @

    1 J4 F& m1 I' A8 C3 V$ ]0 E( C
      o8 d9 W( c: e2 k0 r
    ( C2 }  U0 }! h2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。
    8 X2 ]+ ^: L2 K! ]6 `+ ?# }  x+ [2 d: U! |/ @+ u
    ; k6 ]3 ^+ p6 w2 e/ [
    6 H4 O' x: V0 w/ p; `" |' X# _
    ( O& V' j" S6 n5 i
    ) w8 r7 [( d7 D( s
    11.4 解决方法
    : g4 e" m& }) O/ w1 {" m3 O$ ^+ v& R) [; F
    在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。# \, l8 C( j2 B& W7 d

    - t* J  ?6 U# E' [. C
    • #include <linux/module.h>
    • EXPORT_SYMBOL(__ioremap);6 C# W0 R, I* ?+ g$ E! F+ o( Y
    ' H  L8 U- }6 ^1 u$ v3 R) L% X5 ~* c
    ( F3 D3 D7 E0 T7 `+ |( d

    8 q; L3 i6 K( h/ R* \11.5 小结
    ! o0 v+ m; {6 U7 G  o
    4 H2 r4 U3 ?. k实验步骤5 g. J/ i" \/ K9 {) v
    4 @2 B  n3 |6 \4 Z
    0》virtualbox虚拟机unbuntu上安装nfs服务
    " ^4 g+ j1 x8 p5 w1 j; n9 @) f4 h% ]$ x
    0.0>确保virtualbox能上网
    ' C; J. W0 n( G& B- c8 i
    , l) Y1 Q8 M, s( ~' m, s, s8 o' x+ S( C0.1> apt-get install nfs-kernel-server
    8 G$ a$ R! K' h; t- x) o9 e, t2 q" S; w$ }/ w2 H( m
    0.2>创建nfs共享目录:mkdir /home/openrisc/nfs
    ; d! g+ u( [+ @; v8 U* i5 ?. P! h* E2 p% C; j
    0.3>vim /etc/exports,添加如下内容
    6 z4 D) S4 I/ k. s! Z/ z- |  l1 f" }6 v
    /home/openrisc/nfs  *(rw,sync)
    ; V3 U' ]. _: ^2 `  `; F" E% ~. f2 Z7 ]2 G; C
    0.4>重启nfs服务+ y# X/ {0 i8 l4 N2 e& U- K
    3 X8 }( W7 I: h) t
    sudo /etc/init.d/nfs-kernel-server restart
    4 ]4 o' x  H# z/ `1 ]& O6 Y! K! z7 t; a# ^) Z' S/ E+ p) O! H
    1》修改arch/openrisc/mm/ioremap.c" t: K- `9 u! n9 ?3 F  ~8 ~

    ; ~+ S7 s* b+ @" c/ W3 A2》cd /home/openrisc/soc-design/linux2 c$ H1 v3 ~) A  L, x! Y' N7 t

    ( i5 s4 g! P) r3》make ARCH=openrisc defconfig;make生成vmlinux
    5 u, z4 Z8 z# U' E, r7 ]
    & p7 t% S3 Y5 l7 I2 T0 r: }4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件* x- [  @: L% W0 k. G9 f! }7 |

    ) b; Q1 u3 m$ [3 q/ n# v5》在FPGA板子上运行linux(刚刚生成的vmlinux文件)
    ( q6 g9 }' y  o2 A8 Y
    & A  Z: q: `1 Y+ \6》配置virtualbox的ip
    5 O2 h1 [% S3 {1 U; E) }8 n& z) z! }$ w! j9 E( a% n+ O. |7 c
    sudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.255
    % ~: W2 n9 O0 R, |( r
    + G6 p! u2 q9 ]5 I7》配置PC机的ip为192.168.1.102
    ! q4 o' Y* `1 t; b$ p! E0 H: d9 X( `# h5 H3 X1 p' W
    8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。
    - J$ X( }9 z4 m" G1 u$ O) O) P0 ~% l
    9》板子上执行mkdir nfs,创建本地nfs共享目录6 ^! [7 H' b0 b" m

    % v" Y' J2 n6 y) A8 E, g/ T" ?& v) Q10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs5 j0 A' P! S% {) y3 w) n
    - e9 `8 Y  B& B. l2 r, G: x, d
    11》在virtualbox里将ip_mkg.ko copy到nfs共享目录
    4 M+ Y- S0 J& @' t5 W! s+ g( H1 Q+ q* A6 ]2 D3 N9 `% @/ H% _
    12》板子上cd nfs
    % X" R: X3 r* S7 O5 A, `2 z
    ' T7 x4 h8 [# \& s13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下
    8 y7 |: d0 Q! S& `" k! W1 B* c4 e# N3 Z; o
    14》创建设备节点:mknod /dev/ip_mkg c 102 0
    3 O+ z" k3 V. D" n1 H  U7 X3 ?5 a  ~8 B3 M: L  P
    15》测试:cat /dev/ip_mkg,看到如下结果:
    3 Q* W1 W9 F3 |$ B! b  ^
    ' f6 N0 J" G! Q: `7 `% ?16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下
    . t1 `7 \" X0 g' ~/ W' w+ t& L4 A
    7 V1 G2 m7 s; s1 w$ N( Fsoc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS  R' S  {5 d, D# k  i* s

    : o; |8 l6 n% @\soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。
    0 N8 B% t7 ~- G+ M* K+ I& v( k! ?# ^3 ~; f
    - y, `$ t1 P- r. Z! ?& X

    9 u- V9 O. D+ _& S8 R' ~8 f1 ~- L$ Z8 \; K1 B) a

    ' x0 @$ X' v! j7 J16》运行helloworld2 R) G3 x9 l% n! ?9 a
    8 y  }9 F: ~7 }4 l
    16.1>编写hello.c
    - s  }2 |/ U& c4 ~1 M1 K- x3 s4 c# S* I; @5 D' H
    • #include <stdio.h>
    • void main()
    • {
    • printf("rill helloworld!\n");
    • }( Y+ L7 F/ v; B, v

    # ^# n  a" Y2 y6 \3 e' c4 N9 x
    9 v' D9 q8 N: `1 ?2 E
    2 J( e+ E2 e3 y) ~& [5 \: V% }16.2>编译: or2-linux-gcc hello.c -o hello. d; Q" }9 z% e* Q
    ) U* G# U7 e1 Q. n+ d+ l* e
    16.3>copy到板子上:cp hello /home/openrisc/nfs
    * P7 N( K( t8 X0 J6 M* J1 E& x
    16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:
    - e8 D; T4 v0 X1 ?; ~1 E, R
    5 Y1 J: F9 C7 d: G9 I, J 3 g! C. j" t6 [) ]/ t, i1 E
    & G6 I$ g* ?5 \2 T0 d/ u

    该用户从未签到

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

    本版积分规则

    关闭

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

    EDA365公众号

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

    GMT+8, 2025-6-24 07:02 , Processed in 0.093750 second(s), 26 queries , Gzip On.

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

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

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