当前位置:网站首页>module_ Basic principle of init function
module_ Basic principle of init function
2022-07-19 03:19:00 【Nutshell】
According to the general programming idea , The initialization function of each part will be called in a fixed function, such as :
void init(void)
{
init_a();
init_b();
...
}
What if you add another initialization function , Then again init_b() Add another line after it :
init_c();
This can really complete our functions , But there are certain problems , You cannot add initialization functions independently , Every time you add a new function, you have to modify init function ,blob The initialization function in is completely independent , Just decorate it with a macro :
void init_a(void)
{
}
__initlist(init_a, 1);
It uses this macro to initialize the function list ?
First look __initlist The definition of :
#define __init __attribute__((unused, __section__(".initlist")))
#define __initlist(fn, lvl) /
static initlist_t __init_##fn __init = { /
magic: INIT_MAGIC, /
callback: fn, /
level: lvl }
It seems to define a structure , Stored the pointer of the initialization function , Nothing special . Please note that :section(".initlist")
What does this attribute do ? It tells the connector that this variable is stored in .initlist section , If all initialization functions use this macro , Then each function will have a corresponding initlist_t Structural variables are stored in .initlist section , That is to say, we can be in .initlist Section to find pointers to all initialization functions . How to find .initlist The address of the section ?
extern u32 __initlist_start;
extern u32 __initlist_end;
These two variables work ,__initlist_start yes .initlist The beginning of the section ,__initlist_end It's the end , Through these two variables, we can access all initialization functions .
These two variables are defined there ?
In a connector script file
. = ALIGN(4);
.initlist : {
__initlist_start = .;
*(.initlist)
__initlist_end = .;
}
The values of these two variables are exactly defined in .initlist Start and end address of the section , So we can access all initialization functions through these two variables .
A similar , This method is also used in the kernel , So when we write drivers, we are relatively independent , We don't need to add our own code to call our own initialization function and exit function in a fixed place , The connector has been made for us . Of course module_init There are other features , such as : Our initialization function finishes initialization , The space occupied by the code will be released , Why is that ? It's late today , Write next time. .
linux kernel A large part of the code in is device driver code , These driver codes have initialization and de initialization functions , These codes are usually executed only once , In order to make more efficient use of memory , The memory occupied by these codes can be released .
linux That's what it does , Add __init attribute . stay kernel After initialization , Free the memory space occupied by all these function codes . How does it do it ? seen module_init and module_exit People know , Connector strap __init Attribute functions are placed in the same section in , After using up , The whole section release .
Words alone are no proof , Let's look at the source code ,init/main.c in start_kernel Is to enter kernel One of the first c function , The last line of this function is
rest_init();
static void rest_init(void)
{
kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
unlock_kernel();
cpu_idle();
}
Created a kernel thread , The main function init, The code is as follows :
static int init(void * unused)
{
lock_kernel();
do_basic_setup();
prepare_namespace();
/*
* Ok, we have completed the initial bootup, and
* we're essentially up and running. Get rid of the
* initmem segments and start the user-mode stuff..
*/
free_initmem();
unlock_kernel();
The red line of code is used to release initialization code and data .
void free_initmem(void)
{
#ifndef CONFIG_XIP_ROM
if (!machine_is_integrator()) {
free_area((unsigned long)(&__init_begin),
(unsigned long)(&__init_end),
"init");
}
#endif
}
The next step is kernel Memory management .
stay Linux It's written below driver The module must be familiar with this macro .module_init Macro in MODULE Whether a macro is defined or not, the expanded content is different , If this macro is not defined , Basically, it shows that your module is to be compiled into the kernel (obj-y).
1. stay MODULE There is no definition of this case ,module_init The definition is as follows :
#define module_init(x) __initcall(x);
because
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
therefore ,module_init(x) Finally expanded to :
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
Straighter white dot , Suppose your excellency driver The initialization function of the corresponding module is int gpio_init(void), that module_init(gpio_init) Actually equal to :
static initcall_t __initcall_gpio_init_6 __used attribute((section(".initcall6.init"))) = gpio_init;
Is to declare a type as initcall_t(typedef int (*initcall_t)(void)) Function pointer type variable __initcall_gpio_init_6 And will gpio_init Assignment and it .
The special feature of the function pointer variable declaration here is , Put this variable in a named ".initcall6.init" In the festival . Next combine vmlinux.lds Medium
.initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {
__initcall_start = .;
*(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
__initcall_end = .;
}
as well as do_initcalls:
static void __init do_initcalls(void)
{
initcall_t *call;
for (call = __initcall_start; call < __initcall_end; call++)
do_one_initcall(*call);
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
Then it is not difficult to understand module_init When the initialization function in is called : During system startup
start_kernel()
->rest_init()
->kernel_init()
->kernel_init_freeable()
->do_basic_setup()
->do_initcalls()
2. stay MODULE Defined case ( Most can be dynamically loaded driver Modules belong to this , obj-m),module_init The definition is as follows :
#define module_init(initfn) \
static inline initcall_t __inittest(void) \
{
return initfn; } \
int init_module(void) __attribute__((alias(#initfn)));
The key point of this macro definition is the following sentence , adopt alias take initfn Renamed init_module. The front one __inittest The definition of is actually a skill , Used to correct initfn Do some static type checking , If you define the module initialization function as , such as ,void gpio_init(void) Or is it int gpio_init(int), Then there will be something similar to the following when compiling warning:
GPIO/fsl-gpio.c: In function '__inittest':
GPIO/fsl-gpio.c:46: warning: return from incompatible pointer type
adopt module_init Uniformly alias the module initialization function as init_module, After that insmod When , Called inside the system sys_init_module() Go find init_module Function's entry address .
If objdump -t gpio.ko, You will find init_module and gpio_init At the same address offset . in short , In this case, the initialization function of the module is insmod When is called .
边栏推荐
- [MCU simulation] (XV) instruction system bit operation instructions - bit operation instructions, bit conditional transfer instructions
- Rewrite equals why rewrite hashcode
- 05_ Service call ribbon
- 【单片机仿真】(十一)指令系统逻辑运算指令 — 逻辑与指令ANL、逻辑或指令ORL
- JPA初识(ORM思想、JPA的基本操作)
- Examine your investment path
- [face recognition] face recognition based on histogram histogram with matlab code
- 樂視還有400多比特員工?過著沒有老板的神仙日子 官方出來回應了...
- Bisenetv1 face segmentation
- Polynomial interpolation fitting (II)
猜你喜欢

05_ Service call ribbon

zsh: command not found: mysql

【人脸识别】基于直方图Histogram实现人脸识别附matlab代码

Rtx3090 installing pytorch3d

Transaction and storage engine in MySQL database

GraphQL初识

05_服务调用Ribbon

C language foundation day4 array

Affine transformation implementation

2002 - Can‘t connect to server on ‘127.0.0.1‘ (36)
随机推荐
内置键盘连续444
SQL classic exercises (x30)
【单片机仿真】(二)keil 安装教程
[MCU simulation] (I) proteus8.9 installation tutorial
MySQL optimized index
Need to slow down a little
This is a mathematical problem
SQL经典练习题(x30)
樂視還有400多比特員工?過著沒有老板的神仙日子 官方出來回應了...
数据源对象管理(第三方对象资源) & 加载properties文件
Wechat applet
[NoSQL] redis high availability and persistence
2022-07-16: what is the output of the following go language code? A:[]; B:[5]; C:[5 0 0 0 0]; D:[0 0 0 0 0]。 package main import ( “fmt“ )
We should increase revenue and reduce expenditure
Net SNMP development I
MySQL multi table query
Polynomial interpolation fitting (III)
多表查询——案例练习
Flutter开发:运行flutter upgrade命令报错Exception:Flutter failed to create a directory at…解决方法
Yolov5 ncnn reasoning