Re: [PATCH V2] x86: Allow built-in command line to work in early kernel init

From: Matthew Garrett
Date: Tue May 12 2015 - 14:43:08 EST


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 <asm/cmdline_append.h>
#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 <linux/efi.h>
#include <linux/pci.h>
+#include <asm/cmdline_append.h>
#include <asm/efi.h>
#include <asm/setup.h>
#include <asm/desc.h>
@@ -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 <linux/types.h>
@@ -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 <asm/alternative.h>
#include <asm/prom.h>

+#include <asm/cmdline_append.h>
/*
* 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 <linux/efi.h>
#include <asm/efi.h>
+#include <asm/setup.h>

#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@xxxxxxxxxx
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/