引导期间的内核选项
linux允许用户把内核配置选项传给引导记录,然后引导记录再把选项传给内核。
parse_args函数用于解析输入字符串,输入的字符串内是一些参数,其形式为变量名称=值
,寻找关键字,并开启适当的处理函数。加载模块时,也会用到parse_args,借以解析命令列参数。
函数位置kernel/params.c
注册关键字
内核组件可以利用在include/linux/init.h
中的__setup
宏,注册关键字和相关联的处理函数。
- string: 关键字
- func: 相关联的处理函数
注意事项:string必须以=
字符作结束,以使parse_args
的解析能轻松一点。任何跟在=
之后的文本都将作为输入值传给function_handler。
例子
1
| __setup("netdev=", netdev_boot_setup);
|
其中net_dev_boot_setup
注册成了netdev=
关键字的处理函数。
同一个处理函数可以与几个不同关键字相关联。
当代码编译成模块时,__setup
宏会被忽略(即定义位空)详情可查看include/linux/init.h
使用引导选项配置网络设备
相关结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| /*
* This structure holds at boot time configured netdevice settings. They
* are then used in the device probing.
*/
struct netdev_boot_setup {
char name[IFNAMSIZ];
struct ifmap map;
};
/*
* Device mapping structure. I'd just gone off and designed a
* beautiful scheme using only loadable modules with arguments
* for driver options and along come the PCMCIA people 8)
*
* Ah well. The get() side of this is good for WDSETUP, and it'll
* be handy for debugging things. The set side is fine for now and
* being very small might be worth keeping for clean configuration.
*/
/* for compatibility with glibc net/if.h */
#if __UAPI_DEF_IF_IFMAP
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 */
};
#endif /* __UAPI_DEF_IF_IFMAP */
|
网络设备初始化时,会调用关键字netdev=
注册的处理函数netdev_boot_setup
,将netdev对应的值写到dev_boot_setup对应结构体中的name。
以下为调用流程
net/core/dev.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| #define NETDEV_BOOT_SETUP_MAX 8
/* Boot time configuration table */
static struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX];
__setup("netdev=", netdev_boot_setup);
/*
* Saves at boot time configured settings for any netdevice.
*/
int __init netdev_boot_setup(char *str)
{
int ints[5];
struct ifmap map;
str = get_options(str, ARRAY_SIZE(ints), ints);
if (!str || !*str)
return 0;
/* Save settings */
memset(&map, 0, sizeof(map));
if (ints[0] > 0)
map.irq = ints[1];
if (ints[0] > 1)
map.base_addr = ints[2];
if (ints[0] > 2)
map.mem_start = ints[3];
if (ints[0] > 3)
map.mem_end = ints[4];
/* Add new entry to the list */
return netdev_boot_setup_add(str, &map);
}
/**
* netdev_boot_setup_add - add new setup entry
* @name: name of the device
* @map: configured settings for the device
*
* Adds new setup entry to the dev_boot_setup list. The function
* returns 0 on error and 1 on success. This is a generic routine to
* all netdevices.
*/
static int netdev_boot_setup_add(char *name, struct ifmap *map)
{
struct netdev_boot_setup *s;
int i;
s = dev_boot_setup;
for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) {
if (s[i].name[0] == '\0' || s[i].name[0] == ' ') {
memset(s[i].name, 0, sizeof(s[i].name));
strlcpy(s[i].name, name, IFNAMSIZ);
memcpy(&s[i].map, map, sizeof(s[i].map));
break;
}
}
return i >= NETDEV_BOOT_SETUP_MAX ? 0 : 1;
}
|