linux 内核 module,Linux内核Module详解

Module的一个例子:

创建两个文件

hello.c文件

#include

#include

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);

Makefile可以参考如下

obj-m += hello.o

KERNEL ?= /lib/modules/$(shell uname -r)/build

all:

make -C $(KERNEL) M=$(PWD) modules

clean:

make -C $(KERNEL) M=$(PWD) clean

把hello.c文件和上面的Makefile文件放到同一个目录下

#make命令编译

#su获取root权限

#insmod hello.ko

之后就可以在kernel log里看到输出”Hello, world”,

也可以在#cat /proc/modules 来确认是否已经加到内核

#rummod hello.ko 就可以在kernel log看到输出”Goodbye, cruel world”

module_init宏被定义在kernel/include/linux/init.h文件里

根据是否定义了MODULE,可以分成两个。那MODULE到底有没有定义呢?ARM上面的看来是没有编译,那MODULE宏具体有什么作用呢?后面再说。

MODULE宏这里是有定义的!!

先来看看在MODULE宏没有定义的时候,module_init在kernel/include/linux/init.h文件里的定义形式。

#define module_init(x) __initcall(x);

#define __initcall(fn) device_initcall(fn);

#define device_initcall(fn) __define_initcall(fn, 6);

#define __define_initcall(fn, id) \

static initcall_t __initcall_##fn##id __used \

__attribute__((__section__(".initcall" #id ".init"))) = fn

下面来讲__define_initcall的定义,都代表什么。

static initcall_t 这里 initcall_t的定义是 : typedef int (*initcall_t)(void)

表示后面跟的是一个返回值是int型,且没有参数的一个函数的指针。举一个例子就是mdss_fb_init函数,定义就是

int __init mdss_fb_init(void) { } == 前面__int代表什么呢?后面再说。但返回值是int以及没有参数,都跟上面说明符合,

可以查看一下其他的module_init定义的函数,都是一样的。

上面大概的意思就是定义一个指向函数的指针,以mdss_fb_init为例,就是定义了__initcall_mdss_fb_init6,把mdss_fb_init函数的指针赋给它,

并把__initcall_mdss_fb_init6放到在vmlinux.lds文件里边指定的.initcall6.init区间里边。

下面是生成的vmlinux.lds文件里边的一段。

.init.data : {

*(.init.data) *(.meminit.data) *(.init.rodata) . = ALIGN(8); __start_ftrace_events = .; *(_ftrace_events) __stop_ftrace_events = .; *(.meminit.rodata) . = ALIGN(8); __cpu_method_of_table = .; *(__cpu_method_of_table) __cpu_method_of_table_end = .; . = ALIGN(8); __clksrc_of_table = .; *(__clksrc_of_table) *(__clksrc_of_table_end) . = ALIGN(32); __dtb_start = .; *(.dtb.init.rodata) __dtb_end = .; . = ALIGN(8); __irqchip_begin = .; *(__irqchip_of_table) *(__irqchip_of_end)

. = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .;

__initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;

__con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .;

__compat_exports_start = .; *(.exportcompat.init) __compat_exports_end = .;

__security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .;

. = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info)

}

在生成的System.map里边也可以证明如上所说的说明是正确的。

c115928c T __initcall6_start

……

c11594cc t __initcall_mdss_fb_init6

…….

这里再介绍一下像int __init mdss_fb_init(void) { }这种用包含在module_init里边的函数定义,函数名字前面加上__init到底什么意思。

__init的定义是 #define __init __section(.init.text) __cold notrace。

在定义的init.h文件里边,有对__init的说明如下。

/* These macros are used to mark some functions or * initialized data (doesn't apply to uninitialized data) * as `initialization' functions. The kernel can take this * as hint that the function is used only during the initialization * phase and free up used memory resources after * * Usage: * For functions: * * You should add __init immediately before the function name, like: * * static void __init initme(int x, int y) * { * extern int z; z = x * y; * } * * If the function has a prototype somewhere, you can also add * __init between closing brace of the prototype and semicolon: * * extern int initialize_foobar_device(int, int, int) __init; * * For initialized data: * You should insert __initdata between the variable name and equal * sign followed by value, e.g.: * * static int init_variable __initdata = 0; * static const char linux_logo[] __initconst = { 0x32, 0x36, ... }; * * Don't forget to initialize data not at file scope, i.e. within a function, * as gcc otherwise puts the data into the bss section and not into the init * section. * * Also note, that this data cannot be "const". */

/* These are for everybody (although not all archs will actually discard it in modules) */

#define __init __section(.init.text) __cold notrace //__cold 和notrace具体干嘛的?

#define __initdata __section(.init.data)

#define __initconst __constsection(.init.rodata)

#define __exitdata __section(.exit.data)

#define __exit_call __used __section(.exitcall.exit)

就是说如果某个函数或者变量只在初始化的时候用到,后面可以被清理掉也没有关系的话,就最好定义成上面的一种,以便释放更多空间。

这里具体怎么释放加了上面定义的的函数和变量? 应该是放到了特定区域里边一起释放,具体后面再说。

还有这种__init定义方式需要注意,不要用在函数里边的

__cold表示什么,代码里边有说明,但需要具体解释

/* Mark functions as cold. gcc will assume any path leading to a call

to them will be unlikely. This means a lot of manual unlikely()s

are unnecessary now for any paths leading to the usual suspects

like BUG(), printk(), panic() etc. [but let’s keep them for now for

older compilers]

Early snapshots of gcc 4.3 don’t support this and we can’t detect this

in the preprocessor, but we can live with this because they’re unreleased.

Maketime probing would be overkill here.

gcc also has a attribute((hot)) to move hot functions into

a special section, but I don’t see any sense in this right now in

the kernel context */

#########各种初始化函数的初始化顺序,可以参考下面的定义

#define pure_initcall(fn) __define_initcall(fn, 0)

#define core_initcall(fn) __define_initcall(fn, 1)

#define core_initcall_sync(fn) __define_initcall(fn, 1s)

#define postcore_initcall(fn) __define_initcall(fn, 2)

#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)

#define arch_initcall(fn) __define_initcall(fn, 3)

#define arch_initcall_sync(fn) __define_initcall(fn, 3s)

#define subsys_initcall(fn) __define_initcall(fn, 4)

#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)

#define fs_initcall(fn) __define_initcall(fn, 5)

#define fs_initcall_sync(fn) __define_initcall(fn, 5s)

#define rootfs_initcall(fn) __define_initcall(fn, rootfs)

#define device_initcall(fn) __define_initcall(fn, 6)

#define device_initcall_sync(fn) __define_initcall(fn, 6s)

#define late_initcall(fn) __define_initcall(fn, 7)

#define late_initcall_sync(fn) __define_initcall(fn, 7s)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值