Linux设备驱动开发1-Hello_World

学习任何一门语言,几乎都是从Hello开始的

Posted by Tupelo Shen on February 6, 2020

1 Hello World

学习任何一门语言,几乎都是从Hello World开始的!真是无处不在啊!

代码内容如下:

#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
    printk(KERN_ALERT "Hello, world\n");
    return 0;
}
static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);

这个模块定义了2个函数,一个是模块加载时调用的函数(hello_init);还有一个是卸载模块时调用的函数(hello_exit)。module_initmodule_exit 使用特定的内核宏表明这两个函数的职责。另外,MODULE_LICENSE 告知内核,该模块使用的许可证。

至于具体的每个概念,我们下一章再阐述。

printk 函数类似于C标准库中的 printf 函数。为什么模块能够调用内核的 printk 函数?那是因为模块被使用 insmod 命令加载进入内核后,模块就会被连接到内核,可以访问内核的公共符号(函数和变量)。KERN_ALERT 是消息的优先级。 你可以使用 insmodrmmod 命令加载、卸载模块程序。

值得注意的是,只有root用户具有加载、卸载的权限。

2 主机编译和加载

可以在主机系统上编译运行,其Makefile内容如下:

# 如果定义了KERNELRELEASE,从主机内核系统中调用相应的资源进行编译。
ifneq ($(KERNELRELEASE),)
    obj-m := hello.o
# 否则直接从命令行调用内核构建系统
else
    KERNELDIR ?= /lib/modules/$(shell uname -r)/build   # 指定内核目录
    PWD := $(shell pwd)                                 # 获取当前路径
default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif

编译的结果如下:

make -C /lib/modules/4.15.0-72-generic/build     M=/home/qemu4/qemu/exercise/drivers/hello                                   modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-72-generic'
  CC [M]  /home/qemu4/qemu/exercise/drivers/hello/hello.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/qemu4/qemu/exercise/drivers/hello/hello.mod.o
  LD [M]  /home/qemu4/qemu/exercise/drivers/hello/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-72-generic'

在主机环境上运行,查看效果。

  1. 加载模块

     sudo insmod hello.ko
    
  2. 卸载模块

     sudo rmmod hello
    

如果您正在窗口系统下运行的终端仿真程序运行insmod和rmmod,则屏幕上不会显示任何内容。消息发送到其中一个系统日志文件,例如/var/log/kern.log(这是我的主机环境下的日志文件,实际文件的名称因Linux发行版而异)。其内容如下:

Dec 10 11:27:25 qemu4-VirtualBox kernel: [ 1439.701029] Hello, world
Dec 10 11:27:56 qemu4-VirtualBox kernel: [ 1470.614722] Goodbye, cruel world

3 目标板编译和加载

参考另一篇文章Linux设备驱动开发2-内核编译和加载