任务描述
-
This is Task 01 of the Eudyptula Challenge
-
------------------------------------------
-
-
Write a Linux kernel module, and stand-alone Makefile, that when loaded prints to the kernel debug log level, "Hello World!" Be sure to make the module unloadable as well.
-
-
The Makefile should build the kernel module against the source for the currently running kernel, or, use an environment variable to specify what kernel tree to build it against.
-
简单的介绍下任务:
1、写一个kernel模块,该模块有以下两个基本要求
* 当模块加载的时候,使用DEBUG
LOG LEVEL打印“Hello
World!”
* 该模块能够从内核中被卸载
2、写一个单独的Makefile文件,该文件要能够编译上述编写的模块;并且要以当前运行的内核的代码树来编译此模块
3、证明确实做了上面两件事情
任务实现
按照上面任务的描述,我们实现了对应的如下代码task01和Makefile文件:
task01
-
/*
-
* The test module for the task01 of Eudyptula_challenge.
-
*
-
*
-
* This program is free software; you can redistribute it and/or modify
-
* it under the terms of the GNU General Public License version 2 as
-
* published by the Free Software Foundation.
-
*
-
*/
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
-
-
static int __init task01_module_init(void)
-
{
-
printk (KERN_DEBUG "Hello World!\n");
-
return 0;
-
}
-
-
-
static void __exit task01_module_exit(void)
-
{
-
printk (KERN_DEBUG "Task01 module unloaded!\n");
-
}
-
-
module_init(task01_module_init);
-
module_exit(task01_module_exit);
-
-
MODULE_LICENSE("GPL");
-
MODULE_AUTHOR("Aman <18672988469@sina.cn>");
-
MODULE_DESCRIPTION("Task01 Test Module");
Makefile
-
obj-m+=task01.o
-
-
KDIR:=/lib/modules/$(shell uname -r)/build
-
-
PWD:=$(shell pwd)
-
-
default:
-
$(MAKE) -C $(KDIR) M=$(PWD) modules
-
-
clean:
-
rm -rf Module.symvers Module.markers *.ko *.o *.mod.c .*.cmd .tmp_versions modules.order
任务总结
1 __init && __exit
__init标记的初始化函数,在编译链接的时候会被放到.init.text代码段中,在内核加载完该模块后,会将.init.text中的内容清空,这样能够节省这一部分内存供其他功能使用。
如下为其在代码中的定义: include/linux/init.h
-
#define __init __section(.init.text) __cold notrace
__exit标记只在定义了MODULE的系统中有用,代码如下:include/linux/init.h
-
#ifdef MODULE
-
-
#define __exitused
-
-
#else
-
-
#define __exitused __used
-
-
#endif
-
-
-
-
#define __exit __section(.exit.text) __exitused __cold notrace
因为只有在模块被卸载的情况下,该函数才会被调用,如果该模块被编译进内核,那么该模块永远也不会被卸载,也就没有机会调用。
2 printk
引用《Linux内核驱动模块编写指南》的话,“不管你可能怎么想,printk()并不是设计用来同用户交互的”。因为内核的特殊性和重要性,需要一些方式能够记录其出错以及一些重要的信息并且能够针对一些重要的信息给出警告,而printk就是用来记录这些信息的工具。
内核中有日志级别,而printk中可以定义此次打印的级别,如果定义的级别小于此时内核中默认的打印级别,那么此次打印就能够正常输出。
内核日志级别的定义如下:include/linux/kern_leves.h
-
#define KERN_EMERG KERN_SOH "0" /* system is unusable */
-
-
#define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */
-
-
#define KERN_CRIT KERN_SOH "2" /* critical conditions */
-
-
#define KERN_ERR KERN_SOH "3" /* error conditions */
-
-
#define KERN_WARNING KERN_SOH "4" /* warning conditions */
-
-
#define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */
-
-
#define KERN_INFO KERN_SOH "6" /* informational */
-
-
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
内核中默认的打印级别在如下文件中定义:include/linux/printk.h
-
#define
CONSOLE_LOGLEVEL_DEFAULT 7
可以通过cat
/proc/sys/kernel/printk来查看相应的系统配置。对应的代码在printk.c中的console_printk定义。
-
int console_printk[4] = {
-
-
CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */
-
-
MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */
-
-
CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */
-
-
CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */
-
-
};
3 makefile for linux kernel module
这里要记住就是,多个文件同一个模块(当然包括一个文件一个模块)的makefile的写法
譬如,要最后生成main.ko,而文件是task01.c,那么将上面的Makefile修改如下:
-
obj-m+=main.o
-
-
main-objs := task01.o
-
-
KDIR:=/lib/modules/$(shell uname -r)/build
-
-
PWD:=$(shell pwd)
-
-
default:
-
$(MAKE) -C $(KDIR) M=$(PWD) modules
-
-
clean:
-
rm -rf Module.symvers Module.markers *.ko *.o *.mod.c .*.cmd .tmp_versions modules.order
阅读(2267) | 评论(0) | 转发(0) |