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

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

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

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

    [LV.1]初来乍到

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

    EDA365欢迎您登录!

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

    x

    * [! T" f6 w6 w引言5 e6 S  a5 q& y# {+ j7 c

    . U4 p2 I' {7 h; b我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线inteRFace的ip,可以实现plug & work。
    ( d: Y0 l% N6 J3 b7 S" d
    6 i- U6 i- |1 R+ r/ m6 x6 e所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。$ q7 m5 U% L, i) w3 C

    5 g: p$ N0 ^" z3 J* G  G+ e4 v本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。
      N  h9 |9 P( t0 n0 \$ s' N; d8 `/ l5 c0 b. _4 K6 R

    " n2 v0 j, H  B2 Z6 A2 ^) d1 n
    * @# s! J& r0 o! y, A; m2 S11.1 编写wishbone为interface的ip core(ip_mkg): d# X" T/ k, P8 {- O5 c2 ~

    3 e: N4 G7 f/ g" I1 ]' x1》这一步请参考:
    ! O9 H( w, @, ~- x/ ^0 x1 a
    # l6 l. ^- T# i0 c" o) alinux学习之路_wishbone实验1 e' _! p; S' z4 `( x
    / H) T# C) G, _9 [8 Q/ \
    2》将其中的my_slave_module链接到ORPSoC的wishbone上。
    - j! q' M4 R7 H. o; s$ Z/ |# ]4 f# ~' V' p0 H
    ; X0 y6 ]) e3 L8 n- v2 y1 ]6 l
    & ^. n6 L- |2 p( n) u# h/ Y
    11.2 编写linux下的driver module  K8 Z3 B/ Y0 i

    : }3 q& ?6 m1 ^( V7 w3 |& a- \( x代码及makefile如下:
    , M( @6 d% e" L1 T# z9 U( `' A4 d/ {  h# W! l+ [
    1》ip_mkg.c8 T. }! L/ T! B. Q0 M/ R3 M" D
    + I  ?* f3 _) o3 r/ f1 _

    5 E* O; m( b8 `; F5 Y1 K; t( W! P; G( e6 B
    • /*
    • *
    • * 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");
      ( J( p; k9 m5 O5 k
                        
    ' t/ D. I) B; f: U% H4 }1 Z0 E) l9 Q 0 U6 z7 F1 h  L. `' Q" F8 h, H

    " I" Q6 Z- l3 t, d2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。
    # v- @; t# Y( x$ E! I2 d
    3 M  R0 W$ k0 u9 \: j* I/ L
    • #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
      5 z9 v( `: w# d0 U' H
          
    & K5 W; U$ C* \% O. B$ O. u" i6 Q. j. B5 E  |5 M) w
    7 }  K( [7 T/ ~( P$ `, K+ ?6 _3 D
    3》Makefile% b+ \4 R; w# [8 \; b3 C/ I
    * b* q) t/ z6 [- u+ h, ~6 y# I
    • # 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" ]- n' h8 e/ e( e
          & o- r( A7 Z  f" ?) Y; x9 I; B
    - w- V. c8 q( D  Z$ M
    ( E* Q) }  U+ w. W7 b) p7 u" I
    11.3 遇到的问题' [/ q5 K' o3 t" g

    2 i( A! D" E. g# \1》当在执行make时会遇到如下警告:__ioremap undefined。
    ! \& b" D) O  K
    " @$ I3 y4 n5 H- T
    + ?8 V  ~. l! @2 w# l
    ! ^: Y/ d# y8 R
    1 |8 N. V6 f- r9 q% ]
    6 A4 b' T: O' q- ~' [7 d5 [6 O8 e2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。- Y' K6 J/ g! d. r" v2 T
    " M( y# M5 _+ j
    + Q2 i/ S  d; l/ \& W0 B1 @

    + p. R0 |/ L& e# a) Z. J* V& ~- i2 }! k. f8 p5 T# U

    & B; v, {1 N! k9 g11.4 解决方法( w" z% ]. v) B; k7 `
      r" B- H; v5 y0 y# D+ z
    在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。
    0 z+ Q. B0 {% R9 O5 d
    1 Z8 P  |5 n, J' m
    • #include <linux/module.h>
    • EXPORT_SYMBOL(__ioremap);$ c5 G* I  m2 \
    & T7 D: i3 J& x, j

    # _( }, x. x3 l8 Y" b
    / ]2 f9 \& S/ X% t$ X; j11.5 小结0 @! d  ]6 ^- L

    - t- h" e0 C( L' ^9 S' `1 Y2 H5 K实验步骤# x' Q  B2 j" R' S  @- [
    ! T5 t6 c4 Q3 @* |3 L
    0》virtualbox虚拟机unbuntu上安装nfs服务
    9 ~# B5 D, E4 A% L+ ]
    : Y4 N) I& @- e0.0>确保virtualbox能上网
    # ]% l$ i# E  z7 ]9 l, `, A) D4 V0 G; }; E& Q
    0.1> apt-get install nfs-kernel-server/ C  M; X1 [4 }' r' g8 [
      |& B  c/ T, z$ V) r
    0.2>创建nfs共享目录:mkdir /home/openrisc/nfs1 {! ?- M8 i* m% P
    4 k/ X' k+ Y( M1 G5 c
    0.3>vim /etc/exports,添加如下内容: h/ i# c6 ?; E3 [! d# K

    6 p1 z" l8 D2 R# E/home/openrisc/nfs  *(rw,sync)
    " M, F" U7 T' T2 k, W9 }3 Y. R& f; a
    - n- g* R- a) I0.4>重启nfs服务) V/ j! u+ u) ]

    & v' P) D- g2 X9 _5 Y' Fsudo /etc/init.d/nfs-kernel-server restart
    5 i4 r* H7 L3 b" H6 L
    . ], l0 [2 p2 T3 k- D& V1》修改arch/openrisc/mm/ioremap.c
    1 F+ U9 V( G3 \
    / r% e( d( Q. g' j: a2》cd /home/openrisc/soc-design/linux
    1 o, o# Y( f& x  k( l" M/ W" P: t% B9 \3 c3 T. e0 o5 ?
    3》make ARCH=openrisc defconfig;make生成vmlinux
    6 F* I5 s6 m2 g
    . r1 v1 T3 r2 k: c' |! h2 @4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件
    - I5 e5 l' |$ _, ^; g5 e9 t+ g- J+ h% `  A3 _
    5》在FPGA板子上运行linux(刚刚生成的vmlinux文件)
    2 ~% n" h3 N4 y1 C. o' F$ V( m% [/ d" I0 v, A3 h! J
    6》配置virtualbox的ip# W, r1 |/ d  H( n+ y
    ! w* {8 k: t) A- N0 w
    sudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.255
    % ~% H# A- {+ J. N! ^; A: e7 g" ?$ w' r4 U9 v5 k
    7》配置PC机的ip为192.168.1.102
    / U9 j( \4 X3 [0 s5 `1 I1 [- q# P+ O# y
    8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。
    ' F8 F' @0 q! y( Z7 j, I9 F- y7 f5 Q7 E; ?
    9》板子上执行mkdir nfs,创建本地nfs共享目录
    # g1 u& u4 D: s+ @  w/ j1 S2 e( r2 Q( f8 L# i; K
    10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs
    $ b& d3 p1 d% }. S( l$ q
    ' f. u% h3 D+ Y9 u11》在virtualbox里将ip_mkg.ko copy到nfs共享目录
    3 Q& U0 r. j' \. {' {2 e
    * w2 J3 }2 i# w- m" `( r12》板子上cd nfs
    ; A6 S- e' c; J  [" x) m/ ?" m) d# b, X" v2 x8 V' `
    13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下
    ; l# o" k+ k; H9 y4 y" i6 I! Q, D+ R  [8 I: p) M
    14》创建设备节点:mknod /dev/ip_mkg c 102 0' {  }  U# I, j' Y! Y' e
    + _$ _' Y+ z* |& I. P
    15》测试:cat /dev/ip_mkg,看到如下结果:
    / z: p3 \8 G, Z) o, Q
    ; y7 a2 h8 {9 P4 x  q2 O1 C# C16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下+ p% t) n$ c, I

    & V. |4 n5 l2 ^/ n9 usoc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS
    2 C5 _+ N# h3 B9 h) T/ f7 k# w4 m. L! n
    \soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。
    ) K3 L' Q2 x* L$ w9 Y
    , ^1 O( A& Q+ `! g! T2 b & q/ d+ v8 ?/ U! F. x; L% S+ J' t

    ! f3 y9 H) T9 X( J% g1 t% t* u& @
    0 o, X" M* w% Q$ ~6 {+ h% ?
    # Z2 r: q1 G3 ?$ x5 ?8 I' n6 I* e16》运行helloworld6 d6 u+ }- K/ [. M: Y! I
    - H6 q/ c# V( Y- i) p- B  P
    16.1>编写hello.c
    / S8 K+ S& E% F  S) U. X: F) y$ d4 [" W! c  X7 y# n* p
    • #include <stdio.h>
    • void main()
    • {
    • printf("rill helloworld!\n");
    • }0 D* Y7 d8 o0 _

    8 H& O* k' j4 L8 N& W% S2 E5 Q( h4 {) ~; \. U
    6 Y& Q( Q) c; ]- U: L* c
    16.2>编译: or2-linux-gcc hello.c -o hello
    , C- t  ~5 P$ W2 i5 G6 V% h# X( {3 V' S# j; e  f
    16.3>copy到板子上:cp hello /home/openrisc/nfs
    + A  M9 o& f  w. ?0 Q0 W; E  C" K& J$ ]5 _
    16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:& f- S3 z0 u. M8 a% B
    / z( A% y: h9 X* Q8 z

    4 R$ x: @/ D7 K: ?8 `4 k- C/ E; }: D- N& O5 X& i  G8 d6 q5 U

    该用户从未签到

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

    本版积分规则

    关闭

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

    EDA365公众号

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

    GMT+8, 2025-11-24 13:19 , Processed in 0.171875 second(s), 26 queries , Gzip On.

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

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

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