Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933794AbbELSnF (ORCPT ); Tue, 12 May 2015 14:43:05 -0400 Received: from mail-wi0-f182.google.com ([209.85.212.182]:35656 "EHLO mail-wi0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932870AbbELSm7 (ORCPT ); Tue, 12 May 2015 14:42:59 -0400 MIME-Version: 1.0 In-Reply-To: References: <1428518512-13460-1-git-send-email-mjg59@coreos.com> <1428611100-23337-1-git-send-email-mjg59@srcf.ucam.org> <20150512092821.GA10900@gmail.com> Date: Tue, 12 May 2015 11:42:57 -0700 Message-ID: Subject: Re: [PATCH V2] x86: Allow built-in command line to work in early kernel init From: Matthew Garrett To: Ingo Molnar Cc: Matthew Garrett , x86@kernel.org, hpa@zytor.com, mingo@redhat.com, tglx@linutronix.de, Linux Kernel Mailing List , Matthew Garrett Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 14610 Lines: 464 Ok, maybe something more like this? It even gets rid of some of the #ifdefs in setup.c. diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt index 82fbdbc..22eaecf 100644 --- a/Documentation/x86/zero-page.txt +++ b/Documentation/x86/zero-page.txt @@ -12,6 +12,7 @@ Offset Proto Name Meaning 000/040 ALL screen_info Text mode or frame buffer information (struct screen_info) 040/014 ALL apm_bios_info APM BIOS information (struct apm_bios_info) +054/004 ALL setup_flags Flags passed from early kernel setup 058/008 ALL tboot_addr Physical address of tboot shared page 060/010 ALL ist_info Intel SpeedStep (IST) BIOS support information (struct ist_info) diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index bd49ec6..3718244 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -273,6 +273,7 @@ void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg); /* cmdline.c */ int __cmdline_find_option(unsigned long cmdline_ptr, const char *option, char *buffer, int bufsize); int __cmdline_find_option_bool(unsigned long cmdline_ptr, const char *option); +int __cmdline_init(unsigned long cmdline_ptr, struct boot_params *params); static inline int cmdline_find_option(const char *option, char *buffer, int bufsize) { unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr; @@ -293,6 +294,15 @@ static inline int cmdline_find_option_bool(const char *option) return __cmdline_find_option_bool(cmd_line_ptr, option); } +static inline int cmdline_init(void) +{ + unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr; + + if (cmd_line_ptr >= 0x100000) + return -1; /* inaccessible */ + + return __cmdline_init(cmd_line_ptr, &boot_params); +} /* cpu.c, cpucheck.c */ int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr); int validate_cpu(void); diff --git a/arch/x86/boot/cmdline.c b/arch/x86/boot/cmdline.c index 625d21b..9ddffd0 100644 --- a/arch/x86/boot/cmdline.c +++ b/arch/x86/boot/cmdline.c @@ -12,8 +12,15 @@ * Simple command-line parser for early boot. */ +#include #include "boot.h" +#ifdef CONFIG_CMDLINE_BOOL +static char builtin_cmdline[] = CONFIG_CMDLINE; +#else +static char *builtin_cmdline; +#endif + static inline int myisspace(u8 c) { return c <= ' '; /* Close enough approximation */ @@ -156,3 +163,38 @@ int __cmdline_find_option_bool(unsigned long cmdline_ptr, const char *option) return 0; /* Buffer overrun */ } + +int __cmdline_init(unsigned long cmdline_ptr, struct boot_params *params) +{ + addr_t cptr; + int i = 0; + + if (!builtin_cmdline) + return 0; + + if (!cmdline_ptr) + return -1; /* No command line */ + + set_fs(cmdline_ptr >> 4); + cptr = cmdline_ptr & 0xf; + + if (append_cmdline) { + while (cptr < 0x10000) { + char c = rdfs8(cptr); + if (!c) { + wrfs8(' ', cptr++); + break; + } + cptr++; + } + } + + while (builtin_cmdline[i] && cptr < 0xffff) + wrfs8(builtin_cmdline[i++], cptr++); + + wrfs8('\0', cptr); + + params->setup_flags |= SETUP_CMDLINE_APPENDED; + + return 0; +} diff --git a/arch/x86/boot/compressed/cmdline.c b/arch/x86/boot/compressed/cmdline.c index b68e303..4348828 100644 --- a/arch/x86/boot/compressed/cmdline.c +++ b/arch/x86/boot/compressed/cmdline.c @@ -1,6 +1,6 @@ #include "misc.h" -#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE +#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE || CONFIG_CMDLINE_BOOL static unsigned long fs; static inline void set_fs(unsigned long seg) @@ -12,6 +12,10 @@ static inline char rdfs8(addr_t addr) { return *((char *)(fs + addr)); } +static inline void wrfs8(u8 v, addr_t addr) +{ + *((char *)(fs + addr)) = v; +} #include "../cmdline.c" static unsigned long get_cmd_line_ptr(void) { @@ -30,4 +34,15 @@ int cmdline_find_option_bool(const char *option) return __cmdline_find_option_bool(get_cmd_line_ptr(), option); } +int cmdline_init(void) +{ + if (!(real_mode->setup_flags & SETUP_CMDLINE_APPENDED)) + return __cmdline_init(get_cmd_line_ptr(), real_mode); + return 0; +} +#else +int cmdline_init(void) +{ + return 0; +} #endif diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 48304b8..e44146d 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -1112,6 +1113,9 @@ struct boot_params *make_boot_params(struct efi_config *c) /* Fill in upper bits of command line address, NOP on 32 bit */ boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32; + if (append_cmdline) + boot_params->setup_flags |= SETUP_CMDLINE_APPENDED; + hdr->ramdisk_image = 0; hdr->ramdisk_size = 0; diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index a107b93..832c9a8 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -393,6 +393,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, lines = real_mode->screen_info.orig_video_lines; cols = real_mode->screen_info.orig_video_cols; + cmdline_init(); + console_init(); debug_putstr("early console in decompress_kernel\n"); diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 89dd0d7..1584397 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -48,10 +48,11 @@ static inline void debug_putstr(const char *s) #endif -#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE +#if CONFIG_EARLY_PRINTK || CONFIG_RANDOMIZE_BASE || CONFIG_CMDLINE_BOOL /* cmdline.c */ int cmdline_find_option(const char *option, char *buffer, int bufsize); int cmdline_find_option_bool(const char *option); +int cmdline_init(void); #endif diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c index fd6c9f2..7c24862 100644 --- a/arch/x86/boot/main.c +++ b/arch/x86/boot/main.c @@ -137,6 +137,9 @@ void main(void) /* First, copy the boot header into the "zeropage" */ copy_boot_params(); + /* Handle built-in command line */ + cmdline_init(); + /* Initialize the early-boot console */ console_init(); if (cmdline_find_option_bool("debug")) diff --git a/arch/x86/include/asm/cmdline_append.h b/arch/x86/include/asm/cmdline_append.h new file mode 100644 index 0000000..a57bf7e --- /dev/null +++ b/arch/x86/include/asm/cmdline_append.h @@ -0,0 +1,10 @@ +#ifndef _ASM_X86_CMDLINE_APPEND_H +#define _ASM_X86_CMDLINE_APPEND_H + +#ifdef CONFIG_CMDLINE_OVERRIDE +static char append_cmdline; +#else +static char append_cmdline = 1; +#endif + +#endif /* _ASM_X86_CMDLINE_APPEND_H */ diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h index ab456dc..3fda079 100644 --- a/arch/x86/include/uapi/asm/bootparam.h +++ b/arch/x86/include/uapi/asm/bootparam.h @@ -27,6 +27,9 @@ #define XLF_EFI_HANDOVER_64 (1<<3) #define XLF_EFI_KEXEC (1<<4) +/* setup_flags */ +#define SETUP_CMDLINE_APPENDED (1<<0) + #ifndef __ASSEMBLY__ #include @@ -114,7 +117,7 @@ struct efi_info { struct boot_params { struct screen_info screen_info; /* 0x000 */ struct apm_bios_info apm_bios_info; /* 0x040 */ - __u8 _pad2[4]; /* 0x054 */ + __u32 setup_flags; /* 0x054 */ __u64 tboot_addr; /* 0x058 */ struct ist_info ist_info; /* 0x060 */ __u8 _pad3[16]; /* 0x070 */ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index d74ac33..4c6456d 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -112,6 +112,7 @@ #include #include +#include /* * max_low_pfn_mapped: highest direct mapped pfn under 4GB * max_pfn_mapped: highest direct mapped pfn over 4GB @@ -234,6 +235,8 @@ unsigned long saved_video_mode; static char __initdata command_line[COMMAND_LINE_SIZE]; #ifdef CONFIG_CMDLINE_BOOL static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; +#else +static char *builtin_cmdline; #endif #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) @@ -973,18 +976,21 @@ void __init setup_arch(char **cmdline_p) bss_resource.start = __pa_symbol(__bss_start); bss_resource.end = __pa_symbol(__bss_stop)-1; -#ifdef CONFIG_CMDLINE_BOOL -#ifdef CONFIG_CMDLINE_OVERRIDE - strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); -#else - if (builtin_cmdline[0]) { - /* append boot loader cmdline to builtin */ - strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE); - strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE); - strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); + if (builtin_cmdline) { + /* Fix up the command line if an earlier stage hasn't */ + if (!(boot_params.setup_flags & SETUP_CMDLINE_APPENDED)) { + if (append_cmdline) { + /* append boot loader cmdline to builtin */ + strlcat(builtin_cmdline, " ", + COMMAND_LINE_SIZE); + strlcat(builtin_cmdline, boot_command_line, + COMMAND_LINE_SIZE); + } + + strlcpy(boot_command_line, builtin_cmdline, + COMMAND_LINE_SIZE); + } } -#endif -#endif strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index f07d4a6..743e4a5 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -12,9 +12,22 @@ #include #include +#include #include "efistub.h" +#ifdef CONFIG_CMDLINE_BOOL +static char builtin_cmdline[] = CONFIG_CMDLINE; +#else +static char* builtin_cmdline; +#endif + +#ifdef CONFIG_CMDLINE_OVERRIDE +static bool append_cmdline; +#else +static bool append_cmdline = true; +#endif + /* * Some firmware implementations have problems reading files in one go. * A read chunk size of 1MB seems to work for most platforms. @@ -649,6 +662,21 @@ static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n) return dst; } +static size_t efi_strlcat(char *dest, const char *src, size_t count) +{ + size_t dsize = strlen(dest); + size_t len = strlen(src); + size_t res = dsize + len; + + dest += dsize; + count -= dsize; + if (len >= count) + len = count-1; + memcpy(dest, src, len); + dest[len] = 0; + return res; +} + /* * Convert the unicode UEFI command line to ASCII to pass to kernel. * Size of memory allocated return in *cmd_line_len. @@ -658,42 +686,72 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, efi_loaded_image_t *image, int *cmd_line_len) { + unsigned long cmdline_addr = 0; + int i; + efi_status_t status; const u16 *s2; u8 *s1 = NULL; - unsigned long cmdline_addr = 0; int load_options_chars = image->load_options_size / 2; /* UTF-16 */ const u16 *options = image->load_options; int options_bytes = 0; /* UTF-8 bytes */ int options_chars = 0; /* UTF-16 chars */ - efi_status_t status; u16 zero = 0; - if (options) { - s2 = options; - while (*s2 && *s2 != '\n' - && options_chars < load_options_chars) { - options_bytes += efi_utf8_bytes(*s2++); - options_chars++; + if (!builtin_cmdline || append_cmdline) { + if (options) { + s2 = options; + while (*s2 && *s2 != '\n' + && options_chars < load_options_chars) { + options_bytes += efi_utf8_bytes(*s2++); + options_chars++; + } + } + + if (!options_chars) { + /* No command line options, so return empty string*/ + options = &zero; } - } - if (!options_chars) { - /* No command line options, so return empty string*/ - options = &zero; - } + options_bytes++; /* NUL termination */ - options_bytes++; /* NUL termination */ + if (builtin_cmdline) { + /* Add length of the built-in command line + space */ + options_bytes += strlen(builtin_cmdline); + options_bytes++; + } - status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr); - if (status != EFI_SUCCESS) - return NULL; + status = efi_low_alloc(sys_table_arg, options_bytes, 0, + &cmdline_addr); - s1 = (u8 *)cmdline_addr; - s2 = (const u16 *)options; + if (status != EFI_SUCCESS) + return NULL; - s1 = efi_utf16_to_utf8(s1, s2, options_chars); - *s1 = '\0'; + s1 = (u8 *)cmdline_addr; + s2 = (const u16 *)options; + + s1 = efi_utf16_to_utf8(s1, s2, options_chars); + *s1 = '\0'; + + if (builtin_cmdline) { + efi_strlcat((char *)cmdline_addr, " ", + COMMAND_LINE_SIZE); + efi_strlcat((char *)cmdline_addr, builtin_cmdline, + COMMAND_LINE_SIZE); + } + *cmd_line_len = options_bytes; + } else { + /* Ignore the provided command line, use the built-in one */ + status = efi_low_alloc(sys_table_arg, strlen(builtin_cmdline), + 0, &cmdline_addr); + if (status != EFI_SUCCESS) + return NULL; + while (builtin_cmdline[i] && i < COMMAND_LINE_SIZE) { + ((char *)cmdline_addr)[i] = builtin_cmdline[i]; + i++; + } + ((char *)cmdline_addr)[i] = '\0'; + *cmd_line_len = strlen(builtin_cmdline); + } - *cmd_line_len = options_bytes; return (char *)cmdline_addr; } -- Matthew Garrett | matthew.garrett@coreos.com -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/