[PATCH 2/2 v4] x86/earlyprintk: setup earlyprintk as early as possible

Alexander Kuleshov
2015-05-10T19:14:30Z

As setup_early_printk passed to the early_param, it will be usable only after
'parse_early_param' function will be called from the 'setup_arch'. So we have
earlyprintk during early boot and decompression. Next point after decompression
of the kernel where we can use early_printk is after call of the
'parse_early_param'.

This patch introduces setup_early_serial_console function which will search the
'earlyprintk' parameter in the kernel command line and setup 'earlyprintk'
depends on result. It allows to make 'earlyprintk' usabable after decompression
of the kernel and before parse_early_param will be called. It also must be safe
if CONFIG_CMDLINE_BOOL and CONFIG_CMDLINE_OVERRIDE are set, because the
setup_builtin_cmdline function will be called before setup_early_printk.

Tested it with qemu, so early_printk() is usable and prints to serial console
right after setup_early_printk function called from arch/x86/kerne/head64.c

Changes v1->v2:

* Comment added before the setup_early_printk call;
* Added information about testing to the commit message.

Changes v2->v3:

* Call setup_cmdline before setup_early_printk;
* setup_early_printk call wrapped with the setup_early_serial_console which
checks that 'serial' given to the earlyprintk command line option. This
prevents call of the setup_early_printk with the given pciserial/dbgp/efi,
because they are using early_ioremap.

Changes v3->v4:

* Move setup_early_serial_console from the include/linux/printk.h
to the arch/x86/include/asm/serial.h, because this function is only
for x86 now.

Changes v4->v5:

* Call setup_builtin_cmdline instead of setup_cmdline

Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
---
arch/x86/include/asm/serial.h | 2 ++
arch/x86/kernel/early_printk.c | 25 +++++++++++++++++++++++++
arch/x86/kernel/head32.c | 5 +++++
arch/x86/kernel/head64.c | 8 +++++++-
4 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/serial.h b/arch/x86/include/asm/serial.h
index 8378b8c..be3b73a 100644
--- a/arch/x86/include/asm/serial.h
+++ b/arch/x86/include/asm/serial.h
@@ -26,4 +26,6 @@
{ .uart = 0, BASE_BAUD, 0x3E8, 4, STD_COMX_FLAGS }, /* ttyS2 */ \
{ .uart = 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */

+int __init setup_early_serial_console(void);
+
#endif /* _ASM_X86_SERIAL_H */
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index 89427d8..d7cc0b1 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -385,4 +385,29 @@ static int __init setup_early_printk(char *buf)
return 0;
}

+int __init setup_early_serial_console(void)
+{
+#ifdef CONFIG_EARLY_PRINTK
+ char *arg;
+
+ /*
+ * make sure that we have:
+ * "serial,0x3f8,115200"
+ * "serial,ttyS0,115200"
+ * "ttyS0,115200"
+ */
+ arg = strstr(boot_command_line, "earlyprintk=serial");
+ if (!arg)
+ arg = strstr(boot_command_line, "earlyprintk=ttyS");
+ if (!arg)
+ return -1;
+
+ arg = strstr(boot_command_line, "earlyprintk=");
+ /* += strlen("earlyprintk"); */
+ arg += 12;
+
+ return setup_early_printk(arg);
+#endif
+}
+
early_param("earlyprintk", setup_early_printk);
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index 95eed21..e863ecc 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -32,6 +32,11 @@ static void __init i386_default_early_setup(void)
asmlinkage __visible void __init i386_start_kernel(void)
{
setup_builtin_cmdline();
+ setup_early_serial_console();
+
+ if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG)
+ early_printk("Kernel alive\n");
+
cr4_init_shadow();
sanitize_boot_params(&boot_params);

diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index df290d1..905e602 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -28,6 +28,7 @@
#include <asm/bootparam_utils.h>
#include <asm/microcode.h>
#include <asm/kasan.h>
+#include <asm/serial.h>

/*
* Manage page tables very early on.
@@ -171,7 +172,12 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
load_idt((const struct desc_ptr *)&idt_descr);

copy_bootdata(__va(real_mode_data));
- setup_builtin_cmdline();
+
+ setup_builtin_cmdline();
+ setup_early_serial_console();
+
+ if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG)
+ early_printk("Kernel alive\n");

/*
* Load microcode early on BSP.
--
2.4.0