From: Tom Rini The following is the outcome of talking with David Woodhouse about the need in various parts of the kernel to parse the command line very early and set some options based on what we read. The result is __early_param("arg", fn) based very heavily on the macro of the same name in the arm kernel. The following is the core of these changes, adding the macro, struct and externs to , the parser to init/main.c and converting console= to this format. As a follow on to this thread are patches against all arches (vs 2.6.5-rc2) to use the global define of saved_command_line, add the appropriate bits to arch/$(ARCH)/kernel/vmlinux.lds.S and in some cases, convert params from the old arch-specific variant to the new __early_param way. Russell King said: It definitely wants to be after mem= since mem= modifies the memory layout before bootmem is initialised (and its required to be parsed before bootmem is initialised, so bootmem knows where the memory is.) So we require, in order: - mem= to be parsed - bootmem to be initialised - drivers which want to allocate from bootmem to then be initialised - setup rest of the kernel - final command line parsing which gives us three stages of command line parsing. dwmw2 says: The current __setup() calls are allowed to use bootmem but not slab, and the __early_param() calls aren't even allowed to use bootmem. DESC Properly fixup console= early_param crap EDESC From: Tom Rini OK. After looking harder at the console= stuff, here's what I'm proposing (and, FWIW, I hope Rusty is right and all of the parse_arg stuff can be called very early). - Drop early-param-fixes.patch (or replace with this) From: Tom Rini - In parse_early_options, find the end of each argument (' ') and assume if no space, we are the last arg. After a sucessful call, move past the argument as it might have been spliced up with NULs. - In console_setup, ensure that name and options are NUL-terminated. - Document the restrictions on __early_param calls. --- 25-akpm/include/linux/init.h | 17 +++++++++++++ 25-akpm/init/main.c | 53 ++++++++++++++++++++++++++++++++++++++++++- 25-akpm/kernel/printk.c | 10 +++++--- 3 files changed, 76 insertions(+), 4 deletions(-) diff -puN include/linux/init.h~early-param-core include/linux/init.h --- 25/include/linux/init.h~early-param-core 2004-04-02 10:30:30.689738592 -0800 +++ 25-akpm/include/linux/init.h 2004-04-02 10:31:41.856919536 -0800 @@ -68,6 +68,23 @@ typedef void (*exitcall_t)(void); extern initcall_t __con_initcall_start, __con_initcall_end; extern initcall_t __security_initcall_start, __security_initcall_end; + +/* + * Early command line parameters. We do not allow for spaces in + * our arguments. Functions are allowed to fail (negative return + * value) but must ensure the arg is unchanged, and can only splice + * the arg up, and not rewrite it. + */ +struct early_params { + const char *arg; + int (*fn)(char *p); +}; +extern struct early_params __early_begin, __early_end; +extern void parse_early_options(char **cmdline_p); + +#define __early_param(name,fn) \ +static struct early_params __early_##fn __attribute_used__ \ +__attribute__((__section__("__early_param"))) = { name, fn } #endif #ifndef MODULE diff -puN init/main.c~early-param-core init/main.c --- 25/init/main.c~early-param-core 2004-04-02 10:30:30.690738440 -0800 +++ 25-akpm/init/main.c 2004-04-02 10:31:28.712917728 -0800 @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -107,6 +108,10 @@ extern void time_init(void); void (*late_time_init)(void); extern void softirq_init(void); +/* Stuff for the command line. */ +char saved_command_line[COMMAND_LINE_SIZE]; /* For /proc */ +static char tmp_command_line[COMMAND_LINE_SIZE]; /* Parsed. */ + static char *execute_command; /* Setup configured maximum number of CPUs to activate */ @@ -392,13 +397,59 @@ static void noinline rest_init(void) } /* + * Initial parsing of the command line. We destructivly + * scan the pointer, and take out any params for which we have + * an early handler for. + */ +void __init parse_early_options(char **cmdline_p) +{ + char *from = *cmdline_p; /* Original. */ + char c = ' ', *to = tmp_command_line; /* Parsed. */ + int len = 0; + + /* Save it, if we need to. */ + if (*cmdline_p != saved_command_line) + memcpy(saved_command_line, *cmdline_p, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + + for (;;) { + if (c == ' ') { + struct early_params *p; + + for (p = &__early_begin; p < &__early_end; p++) { + int len = strlen(p->arg); + + if (memcmp(from, p->arg, len) == 0) { + if (to != *cmdline_p) + to -= 1; + from += len; + p->fn(from); + + while (*from != ' ' && *from != '\0') + from++; + break; + } + } + } + c = *from++; + if (!c) + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *to++ = c; + } + + *to = '\0'; + *cmdline_p = tmp_command_line; +} + +/* * Activate the first processor. */ asmlinkage void __init start_kernel(void) { char * command_line; - extern char saved_command_line[]; extern struct kernel_param __start___param[], __stop___param[]; /* * Interrupts are still disabled. Do necessary setups, then diff -puN kernel/printk.c~early-param-core kernel/printk.c --- 25/kernel/printk.c~early-param-core 2004-04-02 10:30:30.691738288 -0800 +++ 25-akpm/kernel/printk.c 2004-04-02 10:31:41.857919384 -0800 @@ -123,7 +123,8 @@ static int __init console_setup(char *st int idx; /* - * Decode str into name, index, options. + * Decode str into name, index, options, ensure name and + * options are NUL-terminated. */ if (str[0] >= '0' && str[0] <= '9') { strcpy(name, "ttyS"); @@ -131,8 +132,11 @@ static int __init console_setup(char *st } else strncpy(name, str, sizeof(name) - 1); name[sizeof(name) - 1] = 0; - if ((options = strchr(str, ',')) != NULL) + if ((options = strchr(str, ',')) != NULL) { *(options++) = 0; + if ((s = strchr(options, ' ')) != NULL) + *s = 0; + } #ifdef __sparc__ if (!strcmp(str, "ttya")) strcpy(name, "ttyS0"); @@ -149,7 +153,7 @@ static int __init console_setup(char *st return 1; } -__setup("console=", console_setup); +__early_param("console=", console_setup); /** * add_preferred_console - add a device to the list of preferred consoles. _