组件初始化基础架构
(一)引导期间内核选项
引导阶段,会调用parse_args两次,负责引导期间配置输入数据。parse_args是一个函数,用于解析输入字符串,输入的字符串是一些参数,寻找特定关键字并启用适当处理的函数
(二)注册关键字
内核组件使用__setup宏,注册关键字和相关联的处理函数:
string是关键字,function_handler是相关联的处理函数。处理函数实例:
net/core/dev.c中
__setup("netdev=", netdev_boot_setup);
两次调用parse_args原因是引导期间选项分成两类:
- 默认选项
使用__setup定义,并且在parse_args第二次被调用时处理。 - 初期选项
内核提供了parse_early_papams选项,这些选项会有一个特殊的标识。内核引导期间,这些选项必须必其他选项更早的处理。
(三)两次调用parse_args
- 第一遍只看必须在初期处理的较高优先级的选项,由一个特殊标志(early)标识。
- 第二遍则会不足所有其他选项。遵循旧模型的所有选项都会在这一遍处理。
旧:
这个区域会在引导阶段结束时释放掉。内核引导后这些选项就不在需要了,用户无法再运行期间查看或修改这些选项。
新:
这个区域不会被释放,内容会输出到/sys,展露给用户。
(四)init.setip
在include\linux\init.h中,存储__setip的两个输入数据
struct obs_kernel_param {
// 关键字
const char *str;
// 处理函数
int (*setup_func)(char *);
// 是否在第一遍检查
int early;
};
- 所有obs_kernel_param会放入一个专用的内存区域。这样做有两个原因:
- 容易遍历所有实例。
- 这些数据结构不再使用的时候,内核可以快速释放所有数据结构。
(五)网络选项初始化配置
ether=和netdev=都使用netdev_boot_setup处理。结果保存在数据结构中:
struct netdev_boot_setup {
// 设备名
char name[IFNAMSIZ];
// 存储输入配置值的数据结构
struct ifmap map;
};
struct ifmap {
unsigned long mem_start;
unsigned long mem_end;
unsigned short base_addr;
unsigned char irq;
unsigned char dma;
unsigned char port;
/* 3 bytes spare */
};