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

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

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

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

    [LV.1]初来乍到

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

    EDA365欢迎您登录!

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

    x

    : P" ^- Y) j, q6 m引言7 }$ t# K+ Q" x; T! ^2 M6 ^6 K
    : G7 w, x" g: ?" u6 L+ D3 n" k
    我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线inteRFace的ip,可以实现plug & work。% U; g+ S2 l7 D& F! q

    - C1 ~9 F1 R6 O6 M; K) G所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。5 P; H; B2 q5 M+ @& N& m
    4 R2 k1 ^3 A8 j6 Z
    本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。% \" R8 W7 w+ c  e% b

    & I& O7 v2 q9 c0 p' \7 O 4 `5 e4 R4 S5 h
    * v$ Q( D" K: N2 g* ?
    11.1 编写wishbone为interface的ip core(ip_mkg)9 [6 Z" a/ C/ c- e  D2 W7 j

    0 E) }) E# A3 @) A1》这一步请参考:
    ' {  w6 g- ]) u3 _- A- b, l4 U4 }& c! a  ~
    linux学习之路_wishbone实验7 x" C& Y0 G/ R7 e1 P% b7 J
    3 A, c/ @0 m1 P% y6 K$ J, }
    2》将其中的my_slave_module链接到ORPSoC的wishbone上。+ P# o4 A4 g. ~2 F, ~7 D5 L3 j
    9 M2 x/ ^* l1 C; b7 {* i+ d# c+ h
    7 ~$ K; }# O4 z" p8 X

    ' t/ b$ V+ c: l2 d/ A+ b2 O% i. K11.2 编写linux下的driver module' b& ~+ v( l' n) x! Z
    " V( w7 x  }% c0 u/ H8 Q1 G
    代码及makefile如下:0 e$ O8 a8 d  Q* W

    , K- q* I" U- u6 n1》ip_mkg.c1 B" g6 o+ |/ k5 p

    ) w$ t, t* D) N4 w / b5 ~3 d& P9 y
    1 B, a$ ]: \* r; L: D" l8 a+ J
    • /*
    • *
    • * 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");
      ) R, w, K- u# {) Q, L9 {* l
                        
    + _  A* ], E9 |% X' j$ J& d& x2 Q6 e3 Z 9 A+ _, J+ z  `; K  P
    / N; x! e4 B- d
    2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。& M3 K: a8 Q; l8 t+ m9 m

    1 N: @" ~* n! [
    • #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
      ! f' t$ Z5 x/ ]1 y
          / \( T: ^; M; q4 \* k/ R

    8 \7 f0 D& ]9 ], e2 ~) S" Z, j9 U$ i" d" a) D/ K
    3》Makefile; i1 u; O8 u8 A0 C4 v

    ; K. b8 [  |0 e) b8 S
    • # 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" w9 ?! j, ]5 @  n+ {
          
    ! h: [, L( l& R( D- u' N. I7 G( t; E: U+ g% S! ~- _* t

    + e* w. ]5 S8 ^# o- [, K2 Q11.3 遇到的问题  e3 [; i! `. G2 ^& H0 c: M

    $ Q0 X! k  b; U, y( k; `1》当在执行make时会遇到如下警告:__ioremap undefined。7 W* K$ K% A) A& V
    + \0 h! {; g6 H1 h4 A7 k: u

    8 ?3 F) }. h3 j9 S
    0 ]8 S' f+ |/ ~8 o! X* l% P" f  P" r+ l

    $ r' y6 ]5 \6 @7 E) H2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。; Q, p4 ~7 g) G0 F: w

    ! R1 E% k% T% m8 |4 ^ : _$ y' K" w6 w, B& [. p
    9 a5 Z0 n  M$ o" \$ v8 d
    * @+ L5 o4 k! c( G2 c0 {& l) E

    2 z' N  ~; n/ ]! d. a8 Y, \11.4 解决方法
    9 e% B& D2 a6 R- \8 M8 N/ f! W, |5 Z0 L4 Z/ L  a
    在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。. ^  Q0 x6 X$ f5 M8 z1 D4 p

    * i- D4 q- U# u  T+ u' Y) u1 t3 U
    • #include <linux/module.h>
    • EXPORT_SYMBOL(__ioremap);
      + J3 {' _+ u7 ~. v

    6 ]1 V) s' h5 t7 E! A/ `9 _: Z; b8 j4 h
    + P& J4 |1 b2 l' r! U, V0 J
    11.5 小结
    . R6 G  f* r0 s9 |. ?% X; ]: A) p
    实验步骤$ _' \% y$ R+ s

    * ]8 ^! E$ ?* g& ^" _" u4 D1 w" Y0》virtualbox虚拟机unbuntu上安装nfs服务
    ' Q% f- @2 }* i! {8 ?+ d6 {4 \/ S( m0 X! p
    0.0>确保virtualbox能上网
    : w; C1 P8 q4 v
    3 H( Z+ h3 u9 |4 e% D& H8 u0 B+ r0.1> apt-get install nfs-kernel-server
    ( _. i8 k. o, [, o6 S5 U# s8 J- F2 X+ E
    0.2>创建nfs共享目录:mkdir /home/openrisc/nfs* L6 b7 }+ k: \1 x

      C( p3 v" q% n$ {1 ]0.3>vim /etc/exports,添加如下内容8 ]* ^' I2 P5 a4 A
      q2 j7 e; J7 @6 c
    /home/openrisc/nfs  *(rw,sync)* @5 X! {, }0 J1 h

    % w) e# H4 O& L/ {; l" Y1 m% n0.4>重启nfs服务# s+ j0 q2 a4 U! ^7 m" q
    ' V+ E1 p9 b! d  P' r
    sudo /etc/init.d/nfs-kernel-server restart
    5 o) g% Y# T1 _+ z' o5 o0 B* B) v
    1》修改arch/openrisc/mm/ioremap.c" f' o% F, V9 z: j: y- V

    ; S  \% }% A7 A( R- ^* W2》cd /home/openrisc/soc-design/linux4 ^/ y& N" h1 G
    + v$ U! k9 p$ Z. P. c% A) s; x
    3》make ARCH=openrisc defconfig;make生成vmlinux
    & ]6 c) o7 X% C; }8 s% s' l6 ?+ ]1 R
    4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件
    6 P( v2 X- Q3 s8 m
    ' _, A$ o4 k7 a9 e: F5》在FPGA板子上运行linux(刚刚生成的vmlinux文件)
    7 v' ^+ a  Q/ h9 C
    * V: b0 ?3 W3 ]0 c- e( d6》配置virtualbox的ip& M( `# h- s- q

    " H% F- B$ n; A; lsudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.255
    ( Q1 I: M- l. q' \$ z/ g2 |; T
    4 T6 B8 L2 t4 X3 Y7》配置PC机的ip为192.168.1.1026 I0 _! c5 F; v
    0 ~5 D' M8 Z0 g6 f5 C3 o2 J2 B3 D- w; S
    8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。
    + o/ I; y" ^$ `+ ], z- f& t8 a; y5 {0 D$ ^
    9》板子上执行mkdir nfs,创建本地nfs共享目录
    ) R8 P7 {$ k2 I5 q
    $ ]" f1 t- R. [% i2 g10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs  L" g) L; J8 D: d( |' t/ f$ B
    ) T4 Q6 g* q. N( Z1 M6 ]2 t' w
    11》在virtualbox里将ip_mkg.ko copy到nfs共享目录
    % _* Z( T5 ?% D
    . |! ?3 b7 @# F12》板子上cd nfs( B# [! u5 S. K% B# N, Y3 q7 `4 E- B

    ; E( e; e7 I/ ?* c: J% u13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下1 n! l3 R8 @* o
    , d  s" g% [9 L- k
    14》创建设备节点:mknod /dev/ip_mkg c 102 04 Q! x4 F- V8 |9 ?- E

    1 p' I# _9 C+ ~7 C* y! {1 `15》测试:cat /dev/ip_mkg,看到如下结果:& y/ D8 y5 Y; {
    ) t5 q3 j+ k) c; l, R  L1 j
    16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下* H, Q8 g$ L; q9 F3 W+ W' T/ u( C

    : f+ L7 a% v* c# Q9 wsoc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS
    3 E/ o  Z0 y  `% j) J1 {+ M
    5 O# d4 Y" l: n* i. H6 e8 W\soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。
    " D& R6 {* W- ~1 a* W3 G7 E* m3 a

    # d5 Z' i% p) i( [+ u
    ( X' \/ I- Z0 A1 s& y4 g. G) u: a1 \% a' a6 k; \9 F, F

    ( [6 b( U+ l$ ~! I3 [% s( W16》运行helloworld- b) X! R. V& z/ \1 _; m
    + _7 ]7 U5 }5 P% l
    16.1>编写hello.c
    1 _; [. P1 n% K" ]  R5 N
    & {4 `& s1 a1 X. B8 Q7 X
    • #include <stdio.h>
    • void main()
    • {
    • printf("rill helloworld!\n");
    • }/ b) ?5 K" E" z2 x5 {8 ~& L

    ) G2 T# p( e& k7 Z
    0 I1 C/ X/ H; B7 I5 K, T5 ~8 H4 e4 P' B- f6 h
    16.2>编译: or2-linux-gcc hello.c -o hello
    ; o7 j6 w: \& \3 B7 s% C& ^  z5 }8 b7 w: C
    16.3>copy到板子上:cp hello /home/openrisc/nfs) P( R: C% \% H/ P: r( _
    7 \  m7 s2 q; s/ b( B+ S) N0 z
    16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:
    , q% |, l; c1 L  ], B$ p1 f( v. T$ v
    2 n, d3 k, X& L4 {
    3 ~/ z( \! f  k9 L# d

    该用户从未签到

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

    本版积分规则

    关闭

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

    EDA365公众号

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

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

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

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

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