内核初始化

2021-01-24, updated 2021-09-12

引导期间的内核选项

linux允许用户把内核配置选项传给引导记录,然后引导记录再把选项传给内核。

parse_args函数用于解析输入字符串,输入的字符串内是一些参数,其形式为变量名称=值,寻找关键字,并开启适当的处理函数。加载模块时,也会用到parse_args,借以解析命令列参数。

函数位置kernel/params.c

注册关键字

内核组件可以利用在include/linux/init.h中的__setup宏,注册关键字和相关联的处理函数。

__setup(str, func)

注意事项:string必须以=字符作结束,以使parse_args的解析能轻松一点。任何跟在=之后的文本都将作为输入值传给function_handler。

例子

__setup("netdev=", netdev_boot_setup);

其中net_dev_boot_setup注册成了netdev=关键字的处理函数。

同一个处理函数可以与几个不同关键字相关联。

当代码编译成模块时,__setup宏会被忽略(即定义位空)详情可查看include/linux/init.h

使用引导选项配置网络设备

相关结构体

/*
 * 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

#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;
}
words: 890 tags: