From: Tom Rini - Remove saved_command_line (and saving of the command line). - Call parse_early_options - Convert mem=, memmap=, acpi=, noapic, highmem=, apic=, and pci= to __early_param (Greg, is this OK? It looks like it after a quick skim). DESC Fixes for __early_param converts EDESC From: Tom Rini OK. One thing which __setup functions are allowed to do, which __early_param are not is to eat the command line (typically foo = strchr(str, ','); *foo++ = 0). So I've audited all of the converts of __setup to __early_param, and got the following: - Drop the hunk of early-param-i386.patch that changes drivers/pci/pci.c - This is a fix for console= which inadvertantly does ... strcpy(name, str, sizeof(name)) ... ... options = strchr(str, ',') ... *options++ = 0; ... fiddle with name ... - Apply the following to get back pci=noacpi being parsed early. I do not know if this option must be called this early, but it was before the early_param stuff, so I assume it was done with reason (tested, and apci=force (needed on my testbox) pci=noacpi works as expected): --- 25-akpm/arch/i386/kernel/apic.c | 2 25-akpm/arch/i386/kernel/setup.c | 301 ++++++++++++++++----------------- 25-akpm/arch/i386/kernel/vmlinux.lds.S | 3 25-akpm/arch/i386/mach-generic/probe.c | 53 ++--- 25-akpm/drivers/pci/pci.c | 2 5 files changed, 180 insertions(+), 181 deletions(-) diff -puN arch/i386/kernel/setup.c~early-param-i386 arch/i386/kernel/setup.c --- 25/arch/i386/kernel/setup.c~early-param-i386 2004-04-02 10:31:55.408859328 -0800 +++ 25-akpm/arch/i386/kernel/setup.c 2004-04-02 10:32:03.176678440 -0800 @@ -127,9 +127,6 @@ unsigned long saved_videomode; #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 -static char command_line[COMMAND_LINE_SIZE]; - char saved_command_line[COMMAND_LINE_SIZE]; - unsigned char __initdata boot_params[PARAM_SIZE]; static struct resource code_resource = { "Kernel code", 0x100000, 0 }; @@ -484,165 +481,177 @@ static void __init setup_memory_region(v print_memory_map(who); } /* setup_memory_region */ +/* + * "mem=nopentium" disables the 4MB page tables. + * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM + * to , overriding the bios size. + * + * HPA tells me bootloaders need to parse mem=, so no new + * option should be mem= [also see Documentation/i386/boot.txt] + */ +static int __init early_mem(char *from) +{ + if (!memcmp(from, "nopentium", 9)) { + clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); + disable_pse = 1; + } else { + /* If the user specifies memory size, we + * limit the BIOS-provided memory map to + * that size. exactmap can be used to specify + * the exact map. mem=number can be used to + * trim the existing memory map. + */ + unsigned long long mem_size; + + mem_size = memparse(from, &from); + limit_regions(mem_size); + printk(KERN_INFO "user-defined physical RAM map:\n"); + print_memory_map("user"); + } + + return 0; +} +__early_param("mem=", early_mem); -static void __init parse_cmdline_early (char ** cmdline_p) +/* + * "memmap=XXX[KkmM][@#$]XXX[KkmM]" defines a memory region from + * to +, overriding the bios size. + */ +static int __init early_memmap(char *from) { - char c = ' ', *to = command_line, *from = saved_command_line; - int len = 0; int userdef = 0; - /* Save unparsed command line copy for /proc/cmdline */ - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; - - for (;;) { - /* - * "mem=nopentium" disables the 4MB page tables. - * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM - * to , overriding the bios size. - * "memmap=XXX[KkmM]@XXX[KkmM]" defines a memory region from - * to +, overriding the bios size. - * - * HPA tells me bootloaders need to parse mem=, so no new - * option should be mem= [also see Documentation/i386/boot.txt] + if (!memcmp(from, "exactmap", 8)) { + e820.nr_map = 0; + userdef = 1; + } else { + /* If the user specifies memory size, we + * limit the BIOS-provided memory map to + * that size. exactmap can be used to specify + * the exact map. mem=number can be used to + * trim the existing memory map. */ - if (c == ' ' && !memcmp(from, "mem=", 4)) { - if (to != command_line) - to--; - if (!memcmp(from+4, "nopentium", 9)) { - from += 9+4; - clear_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability); - disable_pse = 1; - } else { - /* If the user specifies memory size, we - * limit the BIOS-provided memory map to - * that size. exactmap can be used to specify - * the exact map. mem=number can be used to - * trim the existing memory map. - */ - unsigned long long mem_size; - - mem_size = memparse(from+4, &from); - limit_regions(mem_size); - userdef=1; - } + unsigned long long start_at, mem_size; + mem_size = memparse(from, &from); + if (*from == '@') { + start_at = memparse(from + 1, &from); + add_memory_region(start_at, mem_size, E820_RAM); + } else if (*from == '#') { + start_at = memparse(from + 1, &from); + add_memory_region(start_at, mem_size, E820_ACPI); + } else if (*from == '$') { + start_at = memparse(from + 1, &from); + add_memory_region(start_at, mem_size, E820_RESERVED); + } else { + limit_regions(mem_size); + userdef = 1; } + } - if (c == ' ' && !memcmp(from, "memmap=", 7)) { - if (to != command_line) - to--; - if (!memcmp(from+7, "exactmap", 8)) { - from += 8+7; - e820.nr_map = 0; - userdef = 1; - } else { - /* If the user specifies memory size, we - * limit the BIOS-provided memory map to - * that size. exactmap can be used to specify - * the exact map. mem=number can be used to - * trim the existing memory map. - */ - unsigned long long start_at, mem_size; - - mem_size = memparse(from+7, &from); - if (*from == '@') { - start_at = memparse(from+1, &from); - add_memory_region(start_at, mem_size, E820_RAM); - } else if (*from == '#') { - start_at = memparse(from+1, &from); - add_memory_region(start_at, mem_size, E820_ACPI); - } else if (*from == '$') { - start_at = memparse(from+1, &from); - add_memory_region(start_at, mem_size, E820_RESERVED); - } else { - limit_regions(mem_size); - userdef=1; - } - } - } + if (userdef) { + printk(KERN_INFO "user-defined physical RAM map:\n"); + print_memory_map("user"); + } + + return 0; +} +__early_param("memmap=", early_memmap); #ifdef CONFIG_X86_SMP - /* - * If the BIOS enumerates physical processors before logical, - * maxcpus=N at enumeration-time can be used to disable HT. - */ - else if (!memcmp(from, "maxcpus=", 8)) { - extern unsigned int maxcpus; +/* + * If the BIOS enumerates physical processors before logical, + * maxcpus=N at enumeration-time can be used to disable HT. + */ +static int __init early_maxcpus(char *from) +{ + extern unsigned int maxcpus; - maxcpus = simple_strtoul(from + 8, NULL, 0); - } + maxcpus = simple_strtoul(from, NULL, 0); + + return 0; +} +__early_param("maxcpus=", early_maxcpus); #endif + #ifdef CONFIG_ACPI_BOOT - /* "acpi=off" disables both ACPI table parsing and interpreter */ - else if (!memcmp(from, "acpi=off", 8)) { +static int __init early_acpi(char *from) +{ + /* "off" disables both ACPI table parsing and interpreter */ + if (!memcmp(from, "off", 3)) + disable_acpi(); + + /* "force" to over-ride black-list */ + else if (!memcmp(from, "force", 5)) { + acpi_force = 1; + acpi_ht = 1; + acpi_disabled = 0; + } + + /* "strict" disables out-of-spec workarounds */ + else if (!memcmp(from, "strict", 6)) + acpi_strict = 1; + + /* Limit ACPI just to boot-time to enable HT */ + else if (!memcmp(from, "ht", 2)) { + if (!acpi_force) disable_acpi(); - } - - /* acpi=force to over-ride black-list */ - else if (!memcmp(from, "acpi=force", 10)) { - acpi_force = 1; - acpi_ht = 1; - acpi_disabled = 0; - } + acpi_ht = 1; + } - /* acpi=strict disables out-of-spec workarounds */ - else if (!memcmp(from, "acpi=strict", 11)) { - acpi_strict = 1; - } + return 0; +} +__early_param("acpi=", early_acpi); - /* Limit ACPI just to boot-time to enable HT */ - else if (!memcmp(from, "acpi=ht", 7)) { - if (!acpi_force) - disable_acpi(); - acpi_ht = 1; - } +static int __init early_pci_noacpi(char *ign) +{ + acpi_noirq_set(); - /* "pci=noacpi" disables ACPI interrupt routing */ - else if (!memcmp(from, "pci=noacpi", 10)) { - acpi_noirq_set(); - } + return 0; +} +__early_param("pci=noacpi", early_pci_noacpi); - else if (!memcmp(from, "acpi_sci=edge", 13)) - acpi_sci_flags.trigger = 1; +static int __init early_acpi_sci(char *from) +{ + if (!memcmp(from, "edge", 4)) + acpi_sci_flags.trigger = 1; - else if (!memcmp(from, "acpi_sci=level", 14)) - acpi_sci_flags.trigger = 3; + else if (!memcmp(from, "level", 5)) + acpi_sci_flags.trigger = 3; - else if (!memcmp(from, "acpi_sci=high", 13)) - acpi_sci_flags.polarity = 1; + else if (!memcmp(from, "high", 4)) + acpi_sci_flags.polarity = 1; - else if (!memcmp(from, "acpi_sci=low", 12)) - acpi_sci_flags.polarity = 3; + else if (!memcmp(from, "low", 3)) + acpi_sci_flags.polarity = 3; + return 0; +} +__early_param("acpi_sci=", early_acpi_sci); #ifdef CONFIG_X86_LOCAL_APIC - /* disable IO-APIC */ - else if (!memcmp(from, "noapic", 6)) - disable_ioapic_setup(); +/* Disable IO-APIC. */ +static int __init early_disable_ioapic(char *from) +{ + disable_ioapic_setup(); + + return 0; +} +__early_param("noapic", early_disable_ioapic); #endif /* CONFIG_X86_LOCAL_APIC */ #endif /* CONFIG_ACPI_BOOT */ - /* - * highmem=size forces highmem to be exactly 'size' bytes. - * This works even on boxes that have no highmem otherwise. - * This also works to reduce highmem size on bigger boxes. - */ - if (c == ' ' && !memcmp(from, "highmem=", 8)) - highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT; - - c = *(from++); - if (!c) - break; - if (COMMAND_LINE_SIZE <= ++len) - break; - *(to++) = c; - } - *to = '\0'; - *cmdline_p = command_line; - if (userdef) { - printk(KERN_INFO "user-defined physical RAM map:\n"); - print_memory_map("user"); - } +/* + * highmem=size forces highmem to be exactly 'size' bytes. + * This works even on boxes that have no highmem otherwise. + * This also works to reduce highmem size on bigger boxes. + */ +static int __init early_highmem_size(char *from) +{ + highmem_pages = memparse(from, &from) >> PAGE_SHIFT; + + return 0; } +__early_param("highmem=", early_highmem_size); /* * Callback for efi_memory_walk. @@ -1087,6 +1096,7 @@ __setup("noreplacement", noreplacement_s */ void __init setup_arch(char **cmdline_p) { + extern char saved_command_line[]; unsigned long max_low_pfn; memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); @@ -1145,8 +1155,9 @@ void __init setup_arch(char **cmdline_p) data_resource.start = virt_to_phys(_etext); data_resource.end = virt_to_phys(_edata)-1; - parse_cmdline_early(cmdline_p); - + /* We have the original cmdline stored here already. */ + *cmdline_p = saved_command_line; + parse_early_options(cmdline_p); max_low_pfn = setup_memory(); /* @@ -1159,24 +1170,8 @@ void __init setup_arch(char **cmdline_p) #endif paging_init(); -#ifdef CONFIG_EARLY_PRINTK - { - char *s = strstr(*cmdline_p, "earlyprintk="); - if (s) { - extern void setup_early_printk(char *); - - setup_early_printk(s); - printk("early console enabled\n"); - } - } -#endif - - dmi_scan_machine(); -#ifdef CONFIG_X86_GENERICARCH - generic_apic_probe(*cmdline_p); -#endif if (efi_enabled) efi_map_memmap(); diff -puN arch/i386/kernel/vmlinux.lds.S~early-param-i386 arch/i386/kernel/vmlinux.lds.S --- 25/arch/i386/kernel/vmlinux.lds.S~early-param-i386 2004-04-02 10:31:55.410859024 -0800 +++ 25-akpm/arch/i386/kernel/vmlinux.lds.S 2004-04-02 10:31:55.418857808 -0800 @@ -66,6 +66,9 @@ SECTIONS __setup_start = .; .init.setup : { *(.init.setup) } __setup_end = .; + __early_begin = .; + __early_param : { *(__early_param) } + __early_end = .; __start___param = .; __param : { *(__param) } __stop___param = .; diff -puN arch/i386/mach-generic/probe.c~early-param-i386 arch/i386/mach-generic/probe.c --- 25/arch/i386/mach-generic/probe.c~early-param-i386 2004-04-02 10:31:55.411858872 -0800 +++ 25-akpm/arch/i386/mach-generic/probe.c 2004-04-02 10:31:55.419857656 -0800 @@ -28,41 +28,42 @@ struct genapic *apic_probe[] __initdata NULL, }; -void __init generic_apic_probe(char *command_line) -{ - char *s; +static int __init generic_apic_probe(char *command_line) +{ + char *s = command_line; int i; int changed = 0; - s = strstr(command_line, "apic="); - if (s && (s == command_line || isspace(s[-1]))) { - char *p = strchr(s, ' '), old; - if (!p) - p = strchr(s, '\0'); - old = *p; - *p = 0; - for (i = 0; !changed && apic_probe[i]; i++) { - if (!strcmp(apic_probe[i]->name, s+5)) { - changed = 1; - genapic = apic_probe[i]; - } + char *p = strchr(s, ' '), old; + if (!p) + p = strchr(s, '\0'); + old = *p; + *p = 0; + for (i = 0; !changed && apic_probe[i]; i++) { + if (!strcmp(apic_probe[i]->name, s+5)) { + changed = 1; + genapic = apic_probe[i]; } - if (!changed) - printk(KERN_ERR "Unknown genapic `%s' specified.\n", s); - *p = old; - } - for (i = 0; !changed && apic_probe[i]; i++) { + } + if (!changed) + printk(KERN_ERR "Unknown genapic `%s' specified.\n", s); + *p = old; + + for (i = 0; !changed && apic_probe[i]; i++) { if (apic_probe[i]->probe()) { changed = 1; - genapic = apic_probe[i]; - } + genapic = apic_probe[i]; + } } - /* Not visible without early console */ - if (!changed) - panic("Didn't find an APIC driver"); + /* Not visible without early console */ + if (!changed) + panic("Didn't find an APIC driver"); printk(KERN_INFO "Using APIC driver %s\n", genapic->name); -} + + return 0; +} +__early_param("apic=", generic_apic_probe); /* These functions can switch the APIC even after the initial ->probe() */ diff -puN drivers/pci/pci.c~early-param-i386 drivers/pci/pci.c --- 25/drivers/pci/pci.c~early-param-i386 2004-04-02 10:31:55.413858568 -0800 +++ 25-akpm/drivers/pci/pci.c 2004-04-02 10:31:55.419857656 -0800 @@ -767,7 +767,7 @@ static int __devinit pci_setup(char *str device_initcall(pci_init); -__setup("pci=", pci_setup); +__early_param("pci=", pci_setup); #if defined(CONFIG_ISA) || defined(CONFIG_EISA) /* FIXME: Some boxes have multiple ISA bridges! */ diff -puN arch/i386/kernel/apic.c~early-param-i386 arch/i386/kernel/apic.c --- 25/arch/i386/kernel/apic.c~early-param-i386 2004-04-02 10:32:23.813541160 -0800 +++ 25-akpm/arch/i386/kernel/apic.c 2004-04-02 10:32:23.816540704 -0800 @@ -616,7 +616,7 @@ static int __init lapic_disable(char *st clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); return 0; } -__setup("nolapic", lapic_disable); +__early_param("nolapic", lapic_disable); static int __init lapic_enable(char *str) { _