Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754313AbbGAJpw (ORCPT ); Wed, 1 Jul 2015 05:45:52 -0400 Received: from mail-lb0-f182.google.com ([209.85.217.182]:34902 "EHLO mail-lb0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753881AbbGAJnQ (ORCPT ); Wed, 1 Jul 2015 05:43:16 -0400 From: Alexander Kuleshov To: Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" Cc: Greg Kroah-Hartman , Andy Shevchenko , Mark Einon , David Cohen , Borislav Petkov , linux-kernel@vger.kernel.org, Alexander Kuleshov Subject: [PATCH v14 3/4] x86/earlyprintk: setup earlyprintk as early as possible Date: Wed, 1 Jul 2015 15:43:11 +0600 Message-Id: <1435743791-11547-1-git-send-email-kuleshovmail@gmail.com> X-Mailer: git-send-email 2.4.0.GIT In-Reply-To: <1435743760-11376-1-git-send-email-kuleshovmail@gmail.com> References: <1435743760-11376-1-git-send-email-kuleshovmail@gmail.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7903 Lines: 217 The earlyprintk is usable only after the setup_early_printk() will be executed. We pass 'earlyprintk' through the kernel command line, so it will be usable only after the parse_early_param() will be executed. This means that we have usable earlyprintk only during early boot, kernel decompression and after call of the parse_early_param(), but sometimes it is very useful to know what occurs in between. The earlyprintk can allow us to know what occurs after kernel decompression and before parse_early_param() will be called. There are many stuff after the kernel decompression and before the parse_early_param() will be called as memblock usage, early cpu initialization, early ioremap initialization and etc... So earlyprintk allows us to see what's going on there. This patch provides the following stuff: 1. This patch introduces the setup_earlyprintk_console() function, which called arch/x86/kernel/head{32,64}.c, parses kernel command line, tries to find 'earlyprintk' option and calls setup_early_printk() depending on the result. 2. As setup_earlyprintk_console() setups earlyprintk very early, we can't use all console devices for now, but only serial and vga. There is is_earlyprintk_late variable which determines ability to setup earlyprintk for the certain device. 3. Call of the lockdep_init() added to the arch/x86/kernel/head{32,64}.c to prevent call of the register_console before the initialization of lockdep. In other way there we will get: [ 0.000000] WARNING: lockdep init error! lock-(console_sem).lock was acquiredbefore lockdep_init [ 0.000000] Call stack leading to lockdep invocation was: [ 0.000000] [] save_stack_trace+0x2f/0x50 [ 0.000000] [] __lock_acquire+0xa2c/0xf00 [ 0.000000] [] lock_acquire+0xdb/0x2b0 [ 0.000000] [] _raw_spin_lock_irqsave+0x53/0x90 [ 0.000000] [] down+0x16/0x50 [ 0.000000] [] console_lock+0x19/0x60 [ 0.000000] [] register_console+0x116/0x350 [ 0.000000] [] setup_early_printk+0x165/0x467 [ 0.000000] [] setup_early_serial_console+0x56/0x58 [ 0.000000] [] x86_64_start_kernel+0xce/0x110 [ 0.000000] [] 0xffffffffffffffff [ 0.000000] ------------------------ This patch adds lockdep_init() to the arch/x86/kernel/head{32,64}.c, but not removed it from the init/main.c, because there is a couple of architectures which have support of the lockdep, but do not call lockdep_init() in their architecture-dependent code. 4. As setup_earlyprintk_console can be called twice: from setup_earlyprintk_console() and parse_early_param(), additional check is added to the really early consoles to prevent initialization of already initialized consoles. Tested with qemu, so early_printk() is usable and prints to serial console right after setup_early_printk() function called. We will not see earlyprintk messages in the dmesg buffer, because it is too early to initialized log_buf. Signed-off-by: Alexander Kuleshov --- arch/x86/include/asm/setup.h | 6 ++++++ arch/x86/kernel/early_printk.c | 42 +++++++++++++++++++++++++++++++++++------- arch/x86/kernel/head32.c | 4 ++++ arch/x86/kernel/head64.c | 5 +++++ 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index 68d8c05..44f7059 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -127,0 +127,0 @@ asmlinkage void __init x86_64_start_reservations(char *real_mode_data); #endif /* __i386__ */ void __init setup_builtin_cmdline(void); +#ifdef CONFIG_EARLY_PRINTK +/* used by arch/x86/kernel/head{32,64}.c */ +extern int __init setup_earlyprintk_console(void); +#else +static inline int __init setup_earlyprintk_console(void) { return 0; } +#endif /* CONFIG_EARLY_PRINTK */ #endif /* _SETUP */ #else #define RESERVE_BRK(name,sz) \ diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index 89427d8..10d4d82 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -329,6 +329,14 @@ static inline void early_console_register(struct console *con, int keep_early) register_console(early_console); } +/* + * The setup_early_printk can be called from two places: from the + * setup_earlyprintk_console() and the parse_early_param(). In the + * first case it is too early to setup earlyprintk for some devices + * as efi, pciserial and etc., but it can be set for vga and serial. + */ +static bool is_earlyprintk_late = true; + static int __init setup_early_printk(char *buf) { int keep; @@ -342,47 +350,67 @@ static int __init setup_early_printk(char *buf) keep = (strstr(buf, "keep") != NULL); while (*buf != '\0') { - if (!strncmp(buf, "serial", 6)) { + if (!strncmp(buf, "serial", 6) && + early_serial_console.index == -1) { buf += 6; early_serial_init(buf); early_console_register(&early_serial_console, keep); if (!strncmp(buf, ",ttyS", 5)) buf += 5; } - if (!strncmp(buf, "ttyS", 4)) { + if (!strncmp(buf, "ttyS", 4) && + early_serial_console.index == -1) { early_serial_init(buf + 4); early_console_register(&early_serial_console, keep); } #ifdef CONFIG_PCI - if (!strncmp(buf, "pciserial", 9)) { + if (!strncmp(buf, "pciserial", 9) && is_earlyprintk_late) { early_pci_serial_init(buf + 9); early_console_register(&early_serial_console, keep); buf += 9; /* Keep from match the above "serial" */ } #endif if (!strncmp(buf, "vga", 3) && - boot_params.screen_info.orig_video_isVGA == 1) { + boot_params.screen_info.orig_video_isVGA == 1 && + early_vga_console.index == -1) { max_xpos = boot_params.screen_info.orig_video_cols; max_ypos = boot_params.screen_info.orig_video_lines; current_ypos = boot_params.screen_info.orig_y; early_console_register(&early_vga_console, keep); } #ifdef CONFIG_EARLY_PRINTK_DBGP - if (!strncmp(buf, "dbgp", 4) && !early_dbgp_init(buf + 4)) + if (!strncmp(buf, "dbgp", 4) && !early_dbgp_init(buf + 4) && + is_earlyprintk_late) early_console_register(&early_dbgp_console, keep); #endif #ifdef CONFIG_HVC_XEN - if (!strncmp(buf, "xen", 3)) + if (!strncmp(buf, "xen", 3) && is_earlyprintk_late) early_console_register(&xenboot_console, keep); #endif #ifdef CONFIG_EARLY_PRINTK_EFI - if (!strncmp(buf, "efi", 3)) + if (!strncmp(buf, "efi", 3) && is_earlyprintk_late) early_console_register(&early_efi_console, keep); #endif buf++; } + + is_earlyprintk_late = true; + return 0; } early_param("earlyprintk", setup_early_printk); + +int __init setup_earlyprintk_console(void) +{ + char *arg; + + arg = strstr(boot_command_line, "earlyprintk="); + if (!arg) + return -1; + + is_earlyprintk_late = false; + + return setup_early_printk(arg); +} diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index 92e8b5f..64554be 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -32,2 +32,2 @@ static void __init i386_default_early_setup(void) asmlinkage __visible void __init i386_start_kernel(void) { setup_builtin_cmdline(); + lockdep_init(); + setup_earlyprintk_console(); + early_printk("earlyprintk is initialized\n"); + cr4_init_shadow(); sanitize_boot_params(&boot_params); diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 1e5f064..e61e5a8 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -174,0 +174,0 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data) setup_builtin_cmdline(); + lockdep_init(); + setup_earlyprintk_console(); + early_printk("earlyprintk is initialized\n"); + /* * Load microcode early on BSP. */ -- 2.4.0.GIT -- 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/