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

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

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

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

    [LV.1]初来乍到

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

    EDA365欢迎您登录!

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

    x

    6 y1 j  `  L% D4 N" ^& F引言
    : n9 w7 P4 b8 P8 q
    * i! b# q8 c6 U- c我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线inteRFace的ip,可以实现plug & work。
    " g# u) l3 u! u' X: `# E( W8 @: t8 ~) L3 ~9 d: F9 `
    所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。$ w. s& r& x, S4 ]# o5 C4 x  {
    9 t; }7 `: q9 x8 J  s" W7 \
    本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。% o/ _% j2 m1 B: u8 g
    - O# D1 I1 Z6 H: W$ [! Q: W3 i

    ) \0 K1 Y' B, ~0 y
    ' q+ P: P% Q9 }; c# n, D11.1 编写wishbone为interface的ip core(ip_mkg)$ O/ U" s% F: n, k

    $ E& T* R$ {# ~6 w, e1》这一步请参考:; ^0 J/ W/ P' R# }$ B

    ) v5 L! o' k+ {! T6 a0 [1 Y2 Xlinux学习之路_wishbone实验) f: I& p( |, l; s9 Z# a

    $ q7 \% Q. ^4 l( n/ u$ |7 A% b3 k2》将其中的my_slave_module链接到ORPSoC的wishbone上。
    1 A9 y% S; w+ S* T
    + E6 I0 e7 S1 r5 g) A* C  H* L 5 y! M( F' H7 Q2 i( P! b

    8 z7 k  ]- A' I11.2 编写linux下的driver module
    3 s$ V& N2 ^$ a- F7 y" J
    * l; m+ v- K) Z' b3 h, y( \% J代码及makefile如下:  }, w8 |; w% @8 c. |4 @% ?

    ; R( I0 m/ P+ b1》ip_mkg.c) `# ]3 ^- M! `+ X* C$ a

    2 t( \& O& \& ^! s, F. G* S $ E9 n& s( r6 g9 R9 j
    3 b# z3 E5 x4 r9 ^" t/ s( j$ j9 ?
    • /*
    • *
    • * 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");: `7 L2 c4 f1 N; o
                        
    . M$ ~0 P) ~' H% k( L- b; @) X3 j 4 ]5 d1 X4 V5 Z0 x3 a

    ' P2 d8 E2 g# C6 R' P2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。
    $ T3 q' _  b* P* o+ t
    # G" _. g2 E. i" ?
    • #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
      + s1 x  M$ r9 W7 V3 q9 s" u
          ( h& Z/ r; f% [1 f/ N7 ?8 S. R

    , m5 V8 B9 }- t, E
    1 z7 \! k5 Q1 A5 k: m# Y5 O3》Makefile
    : @3 S3 H1 k4 G3 E0 A% f7 M4 P  ~! O4 w$ C; v
    • # 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
      ' i4 T, ]" j: j% l0 W; r# M8 d* R
          - r: V* Q0 A: Q; B

    7 \8 E0 v, w6 \
    1 {& `9 Q' x, n# R0 g11.3 遇到的问题5 J( B& e$ P6 f* d* s& S

    ( O+ i; b/ n# B' V( F1》当在执行make时会遇到如下警告:__ioremap undefined。
    3 @4 b1 x. D$ v/ p. l% m; U- e% N" g6 a" {: v+ l8 r
    - |( e# X6 E$ A- h, c

      L7 {0 G% N2 W
      r6 k" v8 B$ U/ S8 w6 U- \" {2 x  A. w" k0 _* f* @8 A7 z( }
    2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。9 H  ]$ r( q5 M
    ) m; p4 U) H; {7 n. l; Z
    0 U# k2 L1 t, y8 v

    + ?( u# r% r7 d3 C8 m& D+ q4 ^& T, S$ `) Q: S: P" x0 H& z# l
    * I. K  f3 P( G  a) M; A: b
    11.4 解决方法& H8 q' {7 D+ w
    8 ^* F+ _9 i# I6 p1 H! o) {. x
    在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。
    9 \! S1 S1 a! a& K6 r* t7 b; a0 r! G& W" I; j" ^2 R
    • #include <linux/module.h>
    • EXPORT_SYMBOL(__ioremap);% E# a) P) [  N9 O! f; H9 P' ]
    ! Z7 ?1 S+ r. T& q# D

    , A* G% \7 X) Y% T4 z, `  ~" z  D, m( v( B
    11.5 小结$ r# ?$ n  A6 j
    ( E  }" t7 w. o" D* v4 b
    实验步骤1 [6 i- D( B% Z
    0 E0 d# }9 S9 D- @
    0》virtualbox虚拟机unbuntu上安装nfs服务
    7 w: n% ]# n8 G/ `# e% z
      [3 d' [! ?3 p! L0.0>确保virtualbox能上网* t  A, S+ G4 @& b9 h1 C
    ( y3 v$ Q  ?9 X: C# u9 ^1 L; f
    0.1> apt-get install nfs-kernel-server
    0 X/ w7 M5 j  V( K
    ( g  r( m: Z* `" U0.2>创建nfs共享目录:mkdir /home/openrisc/nfs1 w3 ^# f$ y1 }) l! `
    / Q  b8 S+ F0 v8 N
    0.3>vim /etc/exports,添加如下内容
    % m( P4 ?$ y6 l8 ]3 c& c/ K+ d; v1 P4 W! i* s
    /home/openrisc/nfs  *(rw,sync)
    0 n5 J; p) b* P6 o$ i, j/ A: R* U5 X- K- b. }: Q
    0.4>重启nfs服务
    9 f3 n' \# k+ d6 b7 [, E: R2 c% C, _' |! B) |  a5 ?( J2 O
    sudo /etc/init.d/nfs-kernel-server restart
    + ]/ M' P, V8 s* W0 c' m# s/ U9 C1 u
    1》修改arch/openrisc/mm/ioremap.c3 z2 Y* Z* _7 x- A- k- D5 O
    . s  P6 r$ L/ N+ N: J4 |
    2》cd /home/openrisc/soc-design/linux0 z! z  _7 S  z; v9 a, C' L
    - y7 H# S6 H: ?- I$ w
    3》make ARCH=openrisc defconfig;make生成vmlinux0 M- g+ Y, j* i& l; w- G8 U5 |1 H2 p5 z
    + {4 q( u/ \6 F3 F# Z. R" {
    4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件
    8 ?7 ?6 J5 W+ k+ D* f3 U- T% }8 y7 T4 e; n; s: R8 \' h
    5》在FPGA板子上运行linux(刚刚生成的vmlinux文件)5 t( D# ?: g, l* R% N' J' w+ e

    " m, T6 U- D# X# d; e$ l6》配置virtualbox的ip# U+ g6 `$ o' y; u6 U' U6 A* A/ i

    8 a+ s6 k* u! B8 osudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.255, P: R1 k6 t3 ]- ]

    # ^7 u0 m4 ]4 t! |. E( n' f8 J  w7》配置PC机的ip为192.168.1.102
    / d+ m8 s6 j4 }! V! j- q8 N6 |0 S; p% B5 o! R
    8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。
    . i. f( f4 j& C6 P" K% K
    3 O* f( z* ], ]9 H' X; s/ \9》板子上执行mkdir nfs,创建本地nfs共享目录
      ^0 r) s% @, ]
    % f7 Z: I$ J5 O+ x! _( B10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs
    # d% ?" s1 B3 a5 i0 S7 [+ @  D: H% p- B/ L: J4 J. d' G8 @
    11》在virtualbox里将ip_mkg.ko copy到nfs共享目录
    - {! X1 h' |' U5 G) u' L6 i5 I3 W" i8 p& W7 G  X2 J& J1 X' c5 E
    12》板子上cd nfs* A+ Y$ ~% c7 M- U4 f0 M

    4 _& I9 o: r' l! x1 }13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下6 k% c* ]0 Y  s+ y. Y

    1 q8 ?( J. u: x7 t- q- t- ]14》创建设备节点:mknod /dev/ip_mkg c 102 0! t% d2 S( E  O. @1 A7 A

    2 U3 \& B+ w$ o- }15》测试:cat /dev/ip_mkg,看到如下结果:4 }- h* E) Z+ N; k" _" e

    ) V/ w$ `3 @0 ?: P  T( t5 j16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下
    1 n- W; n4 u2 l! _" [
    ' b1 r; [  X" g& K+ c; ksoc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS& B& P, \" O6 K1 N2 C- U: E; J
    ( ^- V( Q+ T8 U
    \soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。
    ! V; S& ?( g$ y
    & M+ m/ K) X/ y( Y9 L: Q
    ) |7 w- a/ F+ E4 B, X7 L
    1 c$ u! A- P2 y! \
    3 x% ]1 P) k0 X" ]7 D" G' g$ ~+ j# @% z0 S$ [& J; y" g7 B3 g7 ?
    16》运行helloworld
    ( j# h/ t* {9 B. m$ q# A( z+ b2 |  B2 c$ T0 E
    16.1>编写hello.c3 m/ j3 e: @7 @+ k+ q$ W
    0 {& ?7 I. V! n% R" U+ o' Q' L# w
    • #include <stdio.h>
    • void main()
    • {
    • printf("rill helloworld!\n");
    • }
      ; U' F3 j( S( M$ K4 q# S; ?( Y

    ( w( |( D2 c2 q
    9 G4 g. _" N; P* b. O& h! Q- w$ F. d* l1 T
    16.2>编译: or2-linux-gcc hello.c -o hello
    3 s) k5 y0 B! l/ e/ V. v* u% |% {3 O. l" E6 A! D1 Y" O
    16.3>copy到板子上:cp hello /home/openrisc/nfs$ ~( p7 e& G7 a2 K' s
    # o9 C. I' p# A$ A5 E* @! _
    16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:6 V( z1 \7 O$ V8 B' s! X

    6 p. B$ x8 ~/ M' |/ {
    " U% Q* G) y1 j' K" P0 v) u- H4 `' N3 ^5 z

    该用户从未签到

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

    本版积分规则

    关闭

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

    EDA365公众号

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

    GMT+8, 2025-11-24 14:37 , Processed in 0.187500 second(s), 26 queries , Gzip On.

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

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

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