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

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

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

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

    [LV.1]初来乍到

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

    EDA365欢迎您登录!

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

    x

    3 m1 w4 d. T4 S引言3 L5 ~" K0 K- B1 Z: o2 r
    " M+ H! G+ A. |# P$ a
    我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线inteRFace的ip,可以实现plug & work。' |! a  H1 w; g) P% p
    " j' _5 G- H* G1 X
    所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。
    ( D  m0 E2 S2 v" e
    ' }: S0 T" y; J4 B/ _本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。
    % V7 D: m0 O; s7 N$ z, P/ \9 A1 v4 I, S, ~
    / b# w5 }% l# i( l% A( h3 [
    0 q7 U; `7 y8 M, Z0 u) r5 U
    11.1 编写wishbone为interface的ip core(ip_mkg)3 a& B' K1 Q4 f9 \' f

    " C: h' c7 O& k5 U& J1》这一步请参考:
    " {9 G( S. t6 I
    % B6 I: M9 E5 U, g4 E% o  flinux学习之路_wishbone实验  N$ o* E: r, X( a: \# O& i

    6 P9 N6 g% u( x3 q2》将其中的my_slave_module链接到ORPSoC的wishbone上。; ~# c, @5 X, Z4 b6 T; v
    3 A2 W7 B; ~/ |) o4 {
    ! M+ Y  a) \1 D7 w
    ( W; Y% r8 u  Y: X  f+ ]
    11.2 编写linux下的driver module
    # s. R) X3 r4 R; R
    % t' T: j( h# m; Y7 w代码及makefile如下:: s+ j- Y: Y5 j
    1 e& z( c9 i9 Y* s( f
    1》ip_mkg.c
    ( Q" C: _3 Z8 K
    % z5 i  ~  T% w' u
    ( P  e* \' t. u' W! ^  Y  ^, e. }$ l$ |
    • /*
    • *
    • * 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");+ O- Q* A! v3 S
                        
    - H2 f4 _* U& _1 g$ K. |% C" D' \% c 1 T1 w1 M$ M. F6 E, P
    2 T5 u8 R$ I6 \' `
    2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。4 v2 y9 h' v4 B
    $ K: W- t% @) m7 K6 [3 V# {8 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$ F" t* y! n( p. ~/ b& }- O
          
    ) K: l6 T# A, n/ m- Q/ y3 ]6 w
    , m; l1 S+ \# q
    3》Makefile: W( P* t) V2 h" m, U3 C! a
    2 C. h. |6 W3 ]- u- Y1 x6 G2 E* ^
    • # 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
      8 H( I) @0 k$ I& f2 y7 ?1 C7 L; {
          * C8 ^3 ?# H/ d4 h+ R/ V% @* `
    3 ^- o0 @: P% ^8 D$ f  g; s( V
      D' i# D/ K2 F2 O: H4 g" m
    11.3 遇到的问题
    4 G* Q, Z* Q* M+ a0 `# e; a2 q  N1 A) N
    1》当在执行make时会遇到如下警告:__ioremap undefined。
    / a$ w& |8 U  {. s1 ]. B! n# i/ h+ h- d5 X4 p! i0 l, m
    : ?# C( {# r+ A- T& h, _

    & k* X6 Y- g, b; X' v1 ]: f
    9 Z0 H, y2 u. F* a. G" v9 F/ ?0 \; @* F9 A8 p
    2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。3 k0 ~$ W. Y3 {! m
    + @% T- x/ a3 A; N) h* K: v

    ) I  x( k  V" @4 @9 m: h4 J' p9 A: q
    ) Q1 q7 i1 P8 c1 j& O8 z& e
    ! Y7 m; B! i! ]# ^! P
    11.4 解决方法# h% P1 ?. B! V" E
    9 O) C% z' C1 Y4 R$ J+ l3 Q" B8 @
    在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。
    3 I/ ]# H/ d; l* Q/ G, j& g) D" t, y4 G+ V* U
    • #include <linux/module.h>
    • EXPORT_SYMBOL(__ioremap);2 C' t0 n" W' i
    $ n1 s9 z) r+ Y

    5 ?7 y% p' z) @; J( Y7 `/ V+ S( U% x
    3 t4 t" ]+ j) ?! w0 B/ D; `11.5 小结
    % F% W5 X/ G4 O% R& e- a+ G# H$ }5 B" H5 i( M6 [( c) w
    实验步骤* h$ t8 E  q; B* b  ]
    6 q( x8 V  }; g/ R, ~, {9 Q! n
    0》virtualbox虚拟机unbuntu上安装nfs服务
    0 v; D: o( d' e7 s9 P9 F, ^- j( T+ K7 }/ |3 d
    0.0>确保virtualbox能上网2 k+ `" p" C  x0 w. y

    / P$ C6 U3 S& j8 F0.1> apt-get install nfs-kernel-server
    ( j, G% A( k0 X- Y, o% W8 P3 m5 l4 l$ X' S6 A& `  d
    0.2>创建nfs共享目录:mkdir /home/openrisc/nfs( d/ F0 O" {. _# d/ k

    , O7 M* y$ I" b3 \0.3>vim /etc/exports,添加如下内容- u$ K' B3 K6 J/ d
    " U" b$ s6 i5 O8 {4 C3 D. ^
    /home/openrisc/nfs  *(rw,sync)
    2 _9 @7 \! B5 Z5 X4 o$ W  e6 e7 G4 [& X" r
    0.4>重启nfs服务
    ' w5 D. b  n' v
    8 c. g4 G8 _% Q4 a0 [# Y* Esudo /etc/init.d/nfs-kernel-server restart0 j$ J, I$ s0 V. G4 G" O
    7 y' X) |/ K% x6 Z% V1 [0 ]
    1》修改arch/openrisc/mm/ioremap.c
    - B7 K& z$ A: g1 g+ k6 h
    0 p( \, @) l- C% @2》cd /home/openrisc/soc-design/linux  p+ V" X' u* \- j' K6 B4 ?8 [) H
    6 f0 u+ P. [# ~3 i/ ~( R5 l3 p7 J  N
    3》make ARCH=openrisc defconfig;make生成vmlinux
    6 x/ s" s- q# E2 l2 E9 v( @
    6 i5 }' A- d4 x8 \" S; D4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件' A' K5 L- s: f0 T2 _+ F4 Y! N
    + k7 ?. K6 Z. Y2 t; i* M) \
    5》在FPGA板子上运行linux(刚刚生成的vmlinux文件)$ `5 s% x9 C# L# a* [' Z
    - \( \% g( ^' @* H3 {
    6》配置virtualbox的ip* f3 [* ]& w+ Y. e7 A% h3 H0 K+ E

    2 Y6 _' q6 Q7 g6 osudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.255, L& D0 g6 [4 j4 ~
    9 M9 g& t6 ]( p5 U4 ^
    7》配置PC机的ip为192.168.1.102
    0 G, t: r4 R- V2 P9 {9 w
    & `: k( d$ Y6 j0 L, `) q8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。; ^( _9 i. {+ e- s  {
    9 v7 r" J: @! L9 Z) a
    9》板子上执行mkdir nfs,创建本地nfs共享目录* @% j0 G) Q9 o2 V! v. k0 e5 }
    3 m0 S5 z, t/ D+ b- y4 z
    10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs% R/ [$ f% j, g+ B1 a) D$ [  o; ^+ p
    + C7 I' t8 ^, s+ b3 j' w* s. ?( L
    11》在virtualbox里将ip_mkg.ko copy到nfs共享目录
    & ~1 M/ Q5 ^& W
    % T0 G- i- l4 |( I" v12》板子上cd nfs
      n/ z0 Q/ J0 j3 F3 ]! G4 R& l  l) q$ G
    13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下* k7 {' V* q& ~* z$ A. v

    8 Q/ N$ ]- |8 o5 r- u14》创建设备节点:mknod /dev/ip_mkg c 102 0
    6 d% n! k% m# }9 i8 J- w/ F7 |
    ' e7 |! q8 G% M: R9 `15》测试:cat /dev/ip_mkg,看到如下结果:
    - u3 x4 O: f4 y6 J% Y" \/ U! ]. n* L: _
    16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下! Q( w  Y8 J8 m$ H0 o

    * m' T4 s& X7 X" W" S) x+ csoc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS
    . Z  `3 ]4 T/ F) r1 c  y
    5 F6 I2 q; D  F$ H+ X& k\soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。 # q1 i7 Y' J4 D9 s
    / I" u7 ~- Q2 R+ F  K0 [
    ! A2 V- Y" H5 z( l  G, l& s- j
    . J, O( j( D, G8 c& e$ I

    1 [* w$ X9 y4 H5 E
    * ^% G# T4 C. N5 B9 Y1 o+ |& @16》运行helloworld
    + j" G% d* N* c9 Z& F( ~
    / |5 ~; k1 T" D/ K16.1>编写hello.c& }- \' @; `! Z
    ( h2 s& ?4 H" {) j7 g
    • #include <stdio.h>
    • void main()
    • {
    • printf("rill helloworld!\n");
    • }; j6 e, x6 b7 [

    * {% q1 X) A. h' B  y+ g, G' n9 a3 H2 K  S6 ?% r

    0 m$ d( d" X# W3 R! B/ m16.2>编译: or2-linux-gcc hello.c -o hello% H3 `* i* P+ f' B
    9 V% R0 [8 Y" U; ^9 a
    16.3>copy到板子上:cp hello /home/openrisc/nfs
    . a# `1 H$ @( ^
    ! j$ y' A. Y8 b! ^16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:
    9 `0 i  u, ~, f  \$ c8 s  p- k7 A) }$ F
    0 ]' J0 i9 ^: x3 F( ]- I  r
    3 J' P, P1 e, @$ e. F

    该用户从未签到

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

    本版积分规则

    关闭

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

    EDA365公众号

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

    GMT+8, 2025-8-18 06:35 , Processed in 0.125000 second(s), 26 queries , Gzip On.

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

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

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