Linux设备驱动第一天学习笔记(如何将系统在开发板上运行起来、驱动开发基本步骤)

如何将系统在开发板上运行起来?
4.0 交叉编译器的获取?厂家提供 网上下载(厂家确认)
4.1 uboot进行操作?
1,解压厂家源码
2,进入源码
3,make distclean 彻底删除源码的目标、临时文件
4,make xxx_config 针对某个CPU和开发板进行配置
5,make编译
6,结果生成u-boot.bin
7,利用厂家提供的烧写方法进行烧写
8,uboot源码/include/configs/xxx.h,硬件相关的头文件信息,也是移植的重点关注的文件,了解当有uboot当前的支持的硬件信息。

4.2 kernel进行操作

1,解压厂家源码
2,进入源码
3,make distclean 彻底删除源码的目标、临时文件,获取最干净的源代码,不要让上一次的编译结果影响到这一次编译
4,make xxx_defconfig 针对某个CPU和开发板进行配置, xxx_defconfig位于arch/arm/configs/目录下面找同名的配置文件.
5,make menuconfig 做三个检查:
检查当前内核是否支持当前CPU架构;
检查当前内核是否支持当前处理器;
The System type(处理器) -> ….
检查当前内核是否支持当前的开发板;
Board selection(开发板)
6,make zImage/make uImage
7,编译结果;arch/arm/boot/zImage(uImage)
8,平台代码文件 arch/arm/mach-处理器名/mach-开发板名.c
多多看这个目录下对应平台下面的文件,这里的文件很多与硬件相关;

4.3 挂接rootfs(根文件系统)

方法一:可以使用厂家提供(厂家的提供的根文件系统非常庞大,里面可能有很多我们用不到的服务);
方法二:鼓励自己制作rootfs,利用busybox;

系统启动时间:uboot时间+内核启动时间+挂接根文件系统时间;

4.4 设置系统启动的参数;
最关键的参数:
bootcmd : 用于加载和引导内核
bootargs:用于给内核传递参数,指示内核将来挂接根文件系统。

给内核传递的方法?切记
方法一:利用uboot的bootargs ,
方法一:如果有的boardloader没有bootargs,可以内核自身传递参数(在源码里面);
在源代码中执行:
make menuconfig
Boot options ->
(console = xxx)Default kernel command string //内核自己给自己传递参数,把光标移动到这个位置,按回车进行修改,例如利用NFS网络启动:root = /dev/nfs nfsroot = 192.168.1.5 保存即可
[] Alwasy use the default dernel commad string //如果选择为*,uboot的bootargs无效,内核自己传递有效;如果不选择,则相反;

4.5 NFS网络文件系统启动的注意事项
1,ubuntu系统必须搭建好NFS网络服务
vim /etc/exports
sudo /etc/init.d/nfs-kernel-server restart
2,配置内核支持NFS网络文件系统
make menuconfig
File system —>
[*] Network File systems —>
[*] Root file system on NFS //必须选中,否则无法挂接NFS网络文件系统

Linux设备驱动开发相关内容:

ARM&Linux工作模式?
SVC(管理)模式、USR模式;
USR模式切换到SVC模式?通过软件中断切换;
当代码在USR模式运行,软件就对应在用户空间运行;
当代码在SVC模式运行,软件就对应在内核空间运行;

用户空间与内核空间:
用户空间:
包含的软件:应用程序(软件)、C库、自己封装制作的动态库
CPU的工作模式:USR
虚拟地址空间范围:0x000,0000~ 0XBFFF,FFFF (3G内存)
采用虚拟内存技术前提是CPU必须集成MMU
用户不能访问内核地址空间,包括代码和数据;
用户不能直接操作硬件资源;
要和内核空间通信必须采用系统调用
要和内核空间进行通信,其实就是CPU工作模式的切换
USR模式与SVC模式的切换采用软中断
内核空间:
包含的软件:进程管理、内存管理、设备驱动、文件系统、TCP/IP网络协议栈
CPU的工作模式:SVC
虚拟地址空间范围为:0xC000,0000 ~ 0xFFF,FFFF(内核1G的虚拟地址空间对于所有进程共享)
能够直接访问硬件资源

总结:用户空间与内核空间划分的目的:实现操作系统的安全保护
用户空间与内核空间划分的依据本质要依赖ARM工作模式
用户空间与内核空间进行数据通信必须利用系统调用

用户 软件编程格式

#include<stdio.h> //标准C的头文件
int main(int argc,char *argv[])//程序入口
{
   printf("hello word! \n");
   return 0;//程序出口
}

内核空间 软件编程格式

#include <linux/module.h>
#include <linux/init.h>//头文件位于内核源码

static int fifth_drv_init(void){
    printk("hello word,%s \n!",__func__);//其中k代表kernel
    return 0;
}
static void fifth_drv_exit(void)
{
}
module_init(fifth_drv_init);//module_init 入
module_exit(fifth_drv_exit);//module_exit 出

入口:通过module_init修饰的函数
出口:通过module_exit修饰的函数
module_init的定义也位于内核源码;

实验:

1,mkdir /opt/drivers/day01/1.0  -p     //  -p, --parents     需要时创建上层目录,如目录早已存在则不当作错误
2, cd   /opt/drivers/day01/1.0 
3, vim helloword
4,保存退出

内核基本编程规范:
1,不允许使用标准C的库和头文件,内核使用的头文件都是位于内核源码
2,内核打印函数不是printf,而是使用内核提供的打印函数printk();打印输出的格式与C一样
3,内核模块代码没有main函数,取而代之的是module_init宏指定的函数为内核模块代码的入口函数;整个软件在运行时,首先运行的是入口函数。
入口函数的返回值:成功返回0 失败返回负值
4,内核模块代码对应的出口是module_exit宏指定的函数;
5,module_init、module_exit的源码同样位于内核源码
6,内核驱动编程一定要注意内存的合法访问,否则会造成系统崩溃
7,内核驱动编程不允许处理float或double
8,进程在用户空间的栈和内核空间的栈是不一样的,内核空间分配8K
9,在编译内核驱动程序时,需要额外编写Makefile,来关联源码。
10,驱动对应的可执行文件为ko结尾,相关操作命令
insmod rmmod lsmmod modinfo
11,内核模块信息 许可声明必须添加 : MODULE_LICENSE(“GPL”);
12,模块的命令行传参
本质目的:在加载模块或模块运行期间(卸载模块之前)能够给模块传递参数信息

笔试题:阐述你对static的认识!

内核模块学源码编译问题:
明确:内核模块源码编译必须要结合内核源代码 /opt/kernel
编译只需在 /opt/drivers/day01/1.0 添加一个Makefile即可:

obj -m += helloword.o #将helloword.c编译成对应的二进制可执行模块文件helloword.ko
KDIR = /opt/kernel  #指定内核源码路径
all :  #伪目标,这里没有依赖
    #make前是tab键而非空格
    make -C $(KDIR) SUBDIRS = $(PWD) modules 
    # -C表示到某个指定的目录下去编译,类似: cd /opt/kernel; make
    # SUBDIRS:指定一个子目录,这个子目录为当前路径。 其中PWD为系统全局环境变量,当前目录;告诉内核源代码,在这个目录下面的文件需要编译成模块
    #采用模块化编译,将.c编译成.ko文件
    #展开为:make -C /opt/kernel SUBDIRS=/opt/drivers/day01/1.0 modules

clean:
    make -C $(KDIR) SUBDIRS = $(PWD) clean

编译:
只需执行make命令即可
结果helloworld.c编译成对应的helloworld.ko文件
注意:在编译helloworld.c之前,如果内核源码没有配置、编译,必须先对其进行配置、编译

调试宏:
FILE,FUNCTION,LINE,DATE,TIME

vim技巧:
如果在同一个文件里面,有重复出现的函数或变量,可以ctrl+n自动补全
行复制:shift+v 选中行,然后上下选择

如何运行使用内核模块可执行文件helloword.ko?内核空间其实就是我们的zImage;

insmod helloword.ko #加载模块到内核中,一旦加载成功,内核首先执行对应的入口函数,如果入口函数返回0,模块加载成功,模块正式投入运行,如果返回一个负数,模块加载失败
rmmod helloword  #用于从内核中卸载模块,当卸载模块时,对应的出口函数被内核执行,一旦卸载,内核就无此模块
lsmod  #查看当前内核有哪些加载的模块
modinfo helloword #查看模块.ko本身的属性或特性

实验步骤:

 1,file helloworld.ko查看模块的属性
 1cp helloworld.ko  /opt/rootfs /   //拷贝到开发板的根文件系统
 2,insmod helloworld.ko
 4,lsmod
 5,rmmod 

可能遇到的问题
问题1:
helloworld: module license ‘unspecified’ taints kernel。
原因:helloworld模块没有指定具体的许可声明。
解决方法:添加 MODULE_LICENSE(“GPL”) ;添加许可信息必须加

问题2:
卸载模块时提示以下信息,无法卸载:rmmod chdir(/lib/modules) no such file….
原因:没有目录
解决方法:
在开发板中执行:mkdir /lib/modules
如果又提示:rmmod chdir(/lib/modules/2.6.3.5) no such file….
在开发板中执行:mkdir /lib/modules/2.6.3.5


内核模块参数

应用程序的命令行传参:

int main(int argc,char *argv[]){//argc 表示参数个数,argv 参数信息
      int a,b,c;
      if(argc<4){
         return  -1;
      }
       //将字符转为整数
      a = strtoul(argv[1],NULL,0);
      b = strtoul(argv[2],NULL,0);
      c = strtoul(argv[3],NULL,0);
      printf("a = %d,b=%b,c=%c",a,b,c);
}

运行 ./a.out 100 200 300

问:内核模块源码对应的ko文件,当在加载时,能够像应用程序的命令行传参一样也传递参数?可以,需要利用内核的模块参数!
内核模块的使用:
目的:能够在加载模块或模块运行期间(只要模块不卸载)能够给模块传递额外的参数信息

static int irq;//0
static char *pstr;//NULL
/**
* module_param(name,type,perm)
* 功能:指定模块参数,用于加载模块时或加载以后传递参数给模块
* name:模块参数的名称
* type:模块参数的数据类型,不允许传浮点数据,如果一定要
*       bool inbool  charp short ushort int uint long ulong
* perm:模块参数的访问权限。权限一般用八进制表示,如 0664 (0表示八进制)
*       如果perm(权限)非0,那么加载模块以后,会在/sys/modules目录下生成一个跟模块名同名的目录,在这个目录的paramter目录下会有一个跟变量名同名的文件,通过修改这个文件可以修改变量的值 
*       如果perm(权限)为0,则不会生成权限文件
**/

module_param(irq,int,0664);//模块参数的声明,0664可读可写
module_param(pstr,charp,0);//模块参数的声明

/* 
*  如irq的权限为 0664,则会生成  /sys/modules/helloworld/parameters/变量名,文件的内容为变量的内容
*  可以通过 "echo 要写入的内容 > /sys/modules/helloworld/parameters/变量名" 修改变量(会修改文件内容)
*/ 

static int fifth_drv_init(void){
    printk("init irq = %d,pstr = %s \n",irq,pstr);
    return 0;
}

static void fifth_drv_exit(void)
{
    printk("exit irq = %d,pstr = %s \n",irq,pstr);
}
module_init(fifth_drv_init);//module_init 入
module_exit(fifth_drv_exit);//module_exit 出

将上述保存退出,然后将文件拷贝到。。。,实验步骤:

insmod helloworld.ko
rmmod helloworld
insmod helloworld.ko irq = 100  pstr = tarena  #传参
cat /sys/modules/helloworld/parameters/irq #查看irq文件的内容
echo 255 > /sys/modules/helloworld/parameters/irq #向文件写入新值
rmmod helloworld #查看输出的值是否发生了变化
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值