2023/7/20 初学内核,记录与分享,感叹内核学了后真的感觉很多东西都通透了,但是难度太大,只能浅浅初探。
前提
内核五大功能
? 进程管理:进程的创建,销毁,调度等功能
注:可中断,不可中断,就是是否被信号打断。从运行状态怎样改到可中断等待态,和不可中断等待态操作系统开始会对每个进程分配一个时间片,当进程里面写了sleep函数,进程由运行到休眠态,但是此时CPU不可能等着。有两种方法,1:根据时间片,CPU自动跳转,2:程序里面自己写能引起CPU调度的代码就可以
? 文件管理:通过文件系统ext2/ext3/ext4 yaff jiffs等来组织管理文件
? 网络管理:通过网络协议栈(OSI,TCP)对数据进程封装和拆解过程(数据发送和接收是通过网卡驱动完成的,网卡驱动不会产生文件(在Linux系统dev下面没有相应的文件),所以不能用open等函数,而是使用的socket)。
? 内存管理:通过内存管理器对用户空间和内核空间内存的申请和释放
? 设备管理: 设备驱动的管理(驱动工程师所对应的)
? 字符设备驱动: (led 鼠标 键盘 lcd touchscreen(触摸屏))
1.按照字节为单位进行访问,顺序访问(有先后顺序去访问)
2.会创建设备文件,open read write close来访问
? **块设备驱动 ** :(camera u盘 emmc)
1.按照块(512字节)(扇区)来访问,可以顺序访问,可以无序访问
2.会创建设备文件,open read write close来访问
? 网卡设备驱动:(猫)
1.按照网络数据包来收发的。
驱动
三要素:入口,出口,许可证
● 入口:资源的申请
● 出口:资源的释放
● 许可证:GPL(写一个模块需要开源,因为Linux系统是开源的,所以需要写许可协议)
1.基础模块
驱动格式
#include <linux/init.h>
#include<linux/module.h>
//__init将hello_init放到.init.text段中
static int __init hello_init(void)
{
return 0;
}
//__exit将hello_exit放到.exit.text段中
static void __exit hello_exit(void)
{
}
//告诉内核驱动的入口地址(函数名为函数首地址)
module_init(hello_init);
//告诉内核驱动的出口地址
module_exit(hello_exit);
//许可证
MODULE_LICENSE("GPL");
makefile格式
//板子内核路径
#KERNEL_PATH=/home/hq/kernel/kernel-3.4.39
//Ubuntu内核的路径
KERNEL_PATH=/lib/modules/$(shell uname -r)/build
PWD=$(shell pwd) //驱动文件的路径
all: //目标
make -C $(KERNEL_PATH) M=$(PWD) modules //(-C:进入顶层目录)
/*注:进入内核目录下执行make modules这条命令
如果不指定 M=$(PWD) 会把内核目录下的.c文件编译生成.ko*/
.PHONY:clean
clean:
make -C $(KERNEL_PATH) M=$(PWD) clean
obj-m = hello.o //指定编译模块的名字
命令的使用
创建索引文件
ctags -R
在终端上
vi -t xxx
在代码中跳转
ctrl + ]
ctrl + t
sudo insmod hello.ko 安装驱动模块
sudo rmmod hello 卸载驱动模块
lsmod 查看模块
dmesg 查看消息
sudo dmesg -C 直接清空消息不回显
sudo dmesg -c 回显后清空
打印函数
概念
1. #include <linux/printk.h> //增加这个头文件
2. printk(KERN_ERR "Fail%d",a);//打印函数,KERN_ERR对应的是内核打印级别
3. grep "printk" * -nR 检索所有的打印函数
vi -t KERN_ERR(查看内核打印级别)
4.
#define KERN_EMERG "<0>" /* system is unusable */(系统不用)
#define KERN_ALERT "<1>" /* action must be taken immediately */(被立即处理)
#define KERN_CRIT "<2>" /* critical conditions */(临界条件,临界资源)
#define KERN_ERR "<3>" /* error conditions */(出错)
#define KERN_WARNING "<4>" /* warning conditions */(警告)
#define KERN_NOTICE "<5>" /* normal but significant condition */(提示)
#define KERN_INFO "<6>" /* informational */(打印信息时候的级别)
#define KERN_DEBUG "<7>" /* debug-level messages */ (调试级别)
0 ------ 7
最高的 最低的
5. 打印显示效果是有优先级的
inux@ubuntu:~$ cat /proc/sys/kernel/printk 查看优先级,分布为以下的四个级别
终端的级别 消息的默认级别 终端的最大级别 终端的最小级别
4 4 1 7
更改方式为 echo 4 3 1 7 > /pro/sys/kernel/printk(切换成su权限)
如果是更改开发板打印级别 vi rootfs/etc/init.d/rcS
echo 4 3 1 7 > /proc/sys/kernel/printk
驱动多文件编译
概念
hello.c add.c
Makefile
obj-m:=demo.o
demo-y+=hello.o add.o
(-y作用:将hello.o add.o放到demo.o中)
最终生成demo.ko文件
举例
#KERNEL_PATH=/home/hq/kernel/kernel-3.4.39
KERNEL_PATH=/lib/modules/$(shell uname -r)/build
PWD=$(shell pwd)
all:
make -C $(KERNEL_PATH) M=$(PWD) modules
.PHONY:clean
clean:
make -C $(KERNEL_PATH) M=$(PWD) clean
obj-m = printkk.o
demo-y+=add.o
demo-y+=sub.o
demo-y+=printk