2025-02-09
学习Linux
内核相关知识从什么角度入手不好把握。有的人喜欢从文档开始看,了解整个内核的体系结构,再看源代码。有的人喜欢一开始就看源代码,不过内核源码有900M
,就算是去除驱动相关代码也有400M
。如果想通过看代码来学习内核,不出几天热情就会消退。内核源码的结构复杂,代码难度也大。新手上来就看源码不合适。后来发现从内核驱动开始入手学习内核源码是一个不错的选择。一方面可以直接上手写代码,完成一个内核驱动也是比较有成就感的事情。另一方面能通过编写内核驱动了解到内核的一些机制和子系统。这样对内核有了一个初步的认识会比较容易坚持下来。
sudo apt install build-essential
sudo apt install device-tree-compiler
sudo apt install linux-headers-$(uname -r)
hello.c
驱动源码#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_init(void) {
printk(KERN_INFO "Hi, hello!\n");
return 0;
}
static void __exit hello_exit(void) {
printk(KERN_INFO "Goodbye, hello!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("your-name");
MODULE_VERSION("v0.0.1");
MODULE_DESCRIPTION("A simple hello kernel module");
首先是引入头文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
接着定义驱动加载和退出时调用的函数。在执行insmod hello.ko
命令加载驱动后会调用static int __init hello_init(void)
在执行rmmod hello.ko
命令卸载驱动后会调用static void __exit hello_exit(void)
。module_init
和module_exit
分别向内核注册驱动初始化
和卸载
函数,这样驱动才能知道该调用哪个函数。
最后的是一些驱动相关的元信息,包括:协议,作者,版本和描述信息。
MODULE_LICENSE("GPL");
MODULE_AUTHOR("your-name");
MODULE_VERSION("v0.0.1");
MODULE_DESCRIPTION("A simple hello kernel module");
Makefile
编译脚本#!/bin/sh
arch = x86
top-dir = $(shell pwd)
kernel-version = $(shell uname -r)
kernel-dir ?= /lib/modules/$(kernel-version)/build
obj-m = hello.o
all:
make -C $(kernel-dir) modules M=$(top-dir)
clean:
rm -f *.o *.ko *.mod *.mod.c *.order *.symvers
make -C $(kernel-dir) clean m=$(top-dir)
kernel-dir
是获取内核驱动的构建目录。在编译的过程中会先进入到内核驱动目录进行构建,再在当前hello.c
目录进行构建hello.ko
驱动。
obj-m
指明编译为一个外部的内核驱动,需要使用insmod
命令进行驱动加载。
最后执行sudo make
命令编译hello.ko
驱动。运行sudo insmod hello.ko
加载驱动。
运行sudo dmesg
查看驱动加载信息,可以在输出的日志看到Hi, hello!
信息。
以上就是一个最简单的内核驱动的实现过程。希望对你有所帮助。