Re: [PATCH] x86/earlyprintk: setup earlyprintk as early as possible

From: Yinghai Lu
Date: Tue Apr 07 2015 - 15:07:37 EST


On Tue, Apr 7, 2015 at 3:31 AM, Alexander Kuleshov
<kuleshovmail@xxxxxxxxx> wrote:

>
> As i already wrote, i tested it for x86_64 and it works. I will put earlyprintk
> setup in the start of the i386_start_kernel, will test it with 32-bit
> and resend two
> patches if they will be good.

No, that is not enough.
early_printk would handle not only serial console with io port accessing.
You need to make sure all other path including pciserial/dbgp/efi is safe.
They are using early_ioremap, and you can not call early_ioremap()
before early_ioremap.

otherwise you may need to just search "serial string in boot command line" like
i did in moving earlycon early patch.

Yinghai
Subject: [PATCH -v5] x86: Setup early console as early as possible in x86_start_kernel()

Analyze "console=uart8250,io,0x3f8,115200n8" in i386_start_kernel/x86_64_start_kernel,
and call setup_early_serial8250_console() to init early serial console.

Only can handle io port kind of 8250, because mmio need ioremap.

Use boot_params.hdr.version instead of adding another variable, Suggested by hpa.
Also need to apply this one after x86 memblock patchset.

-v5: fix check when console string is last one in command line.
should use strchrnul(,' ') instead strchr(,' ') for end searching.

Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>
---
arch/x86/include/asm/setup.h | 2 ++
arch/x86/kernel/head.c | 26 ++++++++++++++++++++++++++
arch/x86/kernel/head32.c | 1 +
arch/x86/kernel/head64.c | 5 ++++-
kernel/printk/printk.c | 11 +++++++----
5 files changed, 40 insertions(+), 5 deletions(-)

Index: linux-2.6/arch/x86/include/asm/setup.h
===================================================================
--- linux-2.6.orig/arch/x86/include/asm/setup.h
+++ linux-2.6/arch/x86/include/asm/setup.h
@@ -40,6 +40,8 @@ static inline void vsmp_init(void) { }
void setup_bios_corruption_check(void);

extern unsigned long saved_video_mode;
+int setup_early_serial8250_console(char *cmdline);
+void setup_early_console(void);

extern void reserve_standard_io_resources(void);
extern void i386_reserve_resources(void);
Index: linux-2.6/arch/x86/kernel/head.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/head.c
+++ linux-2.6/arch/x86/kernel/head.c
@@ -69,3 +69,29 @@ void __init reserve_ebda_region(void)
/* reserve all memory between lowmem and the 1MB mark */
memblock_reserve(lowmem, 0x100000 - lowmem);
}
+
+void __init setup_early_console(void)
+{
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+ char constr[64], *p, *q;
+
+ /* Can not handle mmio type 8250 uart yet, too early */
+ p = strstr(boot_command_line, "console=uart8250,io,");
+ if (!p)
+ p = strstr(boot_command_line, "console=uart,io,");
+ if (!p)
+ return;
+
+ p += 8; /* sizeof "console=" */
+ q = strchrnul(p, ' ');
+ if ((q - p) >= sizeof(constr))
+ return;
+
+ memset(constr, 0, sizeof(constr));
+ memcpy(constr, p, q - p);
+
+ lockdep_init();
+
+ setup_early_serial8250_console(constr);
+#endif
+}
Index: linux-2.6/arch/x86/kernel/head32.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/head32.c
+++ linux-2.6/arch/x86/kernel/head32.c
@@ -33,6 +33,7 @@ asmlinkage __visible void __init i386_st
{
cr4_init_shadow();
sanitize_boot_params(&boot_params);
+ setup_early_console();

/* Call the subarch specific early setup function */
switch (boot_params.hdr.hardware_subarch) {
Index: linux-2.6/arch/x86/kernel/head64.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/head64.c
+++ linux-2.6/arch/x86/kernel/head64.c
@@ -171,6 +171,7 @@ asmlinkage __visible void __init x86_64_
load_idt((const struct desc_ptr *)&idt_descr);

copy_bootdata(__va(real_mode_data));
+ setup_early_console();

/*
* Load microcode early on BSP.
@@ -192,8 +193,10 @@ asmlinkage __visible void __init x86_64_
void __init x86_64_start_reservations(char *real_mode_data)
{
/* version is always not zero if it is copied */
- if (!boot_params.hdr.version)
+ if (!boot_params.hdr.version) {
copy_bootdata(__va(real_mode_data));
+ setup_early_console();
+ }

reserve_ebda_region();

Index: linux-2.6/kernel/printk/printk.c
===================================================================
--- linux-2.6.orig/kernel/printk/printk.c
+++ linux-2.6/kernel/printk/printk.c
@@ -2409,11 +2409,14 @@ void register_console(struct console *ne
struct console_cmdline *c;

if (console_drivers)
- for_each_console(bcon)
- if (WARN(bcon == newcon,
- "console '%s%d' already registered\n",
- bcon->name, bcon->index))
+ for_each_console(bcon) {
+ /* not again */
+ if (bcon == newcon) {
+ printk(KERN_INFO "console '%s%d' already registered\n",
+ bcon->name, bcon->index);
return;
+ }
+ }

/*
* before we register a new CON_BOOT console, make sure we don't