Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

118 views
Skip to first unread message

Alexander Kuleshov

unread,
Apr 6, 2015, 9:20:05 AM4/6/15
to
As setup_earlyprintk 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 removes 'earlyprintk' from the early_param and setup it right after
boot data copying. So 'early_printk' function will be usabable after
decompression of kernel and before parse_early_param will be called.

Signed-off-by: Alexander Kuleshov <kulesh...@gmail.com>
---
arch/x86/kernel/early_printk.c | 4 +---
arch/x86/kernel/head64.c | 1 +
include/linux/printk.h | 1 +
3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index a62536a..4b0577b 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -329,7 +329,7 @@ static inline void early_console_register(struct console *con, int keep_early)
register_console(early_console);
}

-static int __init setup_early_printk(char *buf)
+int __init setup_early_printk(char *buf)
{
int keep;

@@ -390,5 +390,3 @@ static int __init setup_early_printk(char *buf)
}
return 0;
}
-
-early_param("earlyprintk", setup_early_printk);
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index c4f8d46..0141de7 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -171,6 +171,7 @@ 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_early_printk(boot_command_line);

/*
* Load microcode early on BSP.
diff --git a/include/linux/printk.h b/include/linux/printk.h
index baa3f97..47e3919 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -115,6 +115,7 @@ int no_printk(const char *fmt, ...)
#ifdef CONFIG_EARLY_PRINTK
extern asmlinkage __printf(1, 2)
void early_printk(const char *fmt, ...);
+int setup_early_printk(char *buf);
#else
static inline __printf(1, 2) __cold
void early_printk(const char *s, ...) { }
--
2.3.3.611.g09038fc.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Ingo Molnar

unread,
Apr 7, 2015, 6:00:05 AM4/7/15
to
This looks useful.

It would be nice to test it via a well placed printk() and check that
before the patch the message doesn't go to the serial console and
after the patch the message indeed arrives on the early serial console
- or something like that.

Thanks,

Ingo

Alexander Kuleshov

unread,
Apr 7, 2015, 6:20:05 AM4/7/15
to
2015-04-07 15:52 GMT+06:00 Ingo Molnar <mi...@kernel.org>:
>
> It would be nice to test it via a well placed printk() and check that
> before the patch the message doesn't go to the serial console and
> after the patch the message indeed arrives on the early serial console
> - or something like that.

I have tested this patch when i wrote it and early_printk does not print
anything before the parse_early_param. But i don't know how to show this
in code in a correct way. Maybe we should to give back early_printk call
which i removed in the previous patch
(https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=91d8f0416f3989e248d3a3d3efb821eda10a85d2)?

Any one another question about this. I submited patch only for head64.c
and it does not affect kernel for i386, because i'm not sure where is
the best place to setup earlyprintk in the head32.c. I thought to put
it in the start of i386_start_kernel(void) (from head32.c) but not sure
about it.

Ingo Molnar

unread,
Apr 7, 2015, 6:30:06 AM4/7/15
to

* Alexander Kuleshov <kulesh...@gmail.com> wrote:

> 2015-04-07 15:52 GMT+06:00 Ingo Molnar <mi...@kernel.org>:
> >
> > It would be nice to test it via a well placed printk() and check that
> > before the patch the message doesn't go to the serial console and
> > after the patch the message indeed arrives on the early serial console
> > - or something like that.
>
> I have tested this patch when i wrote it and early_printk does not print
> anything before the parse_early_param. But i don't know how to show this
> in code in a correct way. [...]

Just add a debug printk() for your own testing, right after the param
initialization call, to be confident that the early console indeed
works.

> which i removed in the previous patch
> (https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=91d8f0416f3989e248d3a3d3efb821eda10a85d2)?
>
> Any one another question about this. I submited patch only for
> head64.c and it does not affect kernel for i386, because i'm not
> sure where is the best place to setup earlyprintk in the head32.c. I
> thought to put it in the start of i386_start_kernel(void) (from
> head32.c) but not sure about it.

I'd use i386_start_kernel() on 32-bit and x86_64_start_kernel() on
64-bit - but I haven't tested whether it actually works.

Thanks,

Ingo

Ingo Molnar

unread,
Apr 7, 2015, 6:40:05 AM4/7/15
to

* Alexander Kuleshov <kulesh...@gmail.com> wrote:

> > Ingo Molnar <mi...@kernel.org>: wrote:
> >
> > Just add a debug printk() for your own testing, right after the param
> > initialization call, to be confident that the early console indeed
> > works.
> >
>
> I already tested it as you said when was writing this patch and it works.

The changelog does not tell us this and it should.

Alexander Kuleshov

unread,
Apr 7, 2015, 6:40:06 AM4/7/15
to
> Ingo Molnar <mi...@kernel.org>: wrote:
>
> Just add a debug printk() for your own testing, right after the param
> initialization call, to be confident that the early console indeed
> works.
>

I already tested it as you said when was writing this patch and it works.

>
> I'd use i386_start_kernel() on 32-bit and x86_64_start_kernel() on
> 64-bit - but I haven't tested whether it actually works.
>

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.

Yinghai Lu

unread,
Apr 7, 2015, 3:10:07 PM4/7/15
to
On Tue, Apr 7, 2015 at 3:31 AM, Alexander Kuleshov
<kulesh...@gmail.com> 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
setup_early_console_x1_pa_symbol_before_earlcon.patch

Yinghai Lu

unread,
Apr 7, 2015, 3:10:08 PM4/7/15
to
On Tue, Apr 7, 2015 at 12:07 PM, Yinghai Lu <yin...@kernel.org> wrote:
> On Tue, Apr 7, 2015 at 3:31 AM, Alexander Kuleshov
> <kulesh...@gmail.com> 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.

They are using early_ioremap, and you can not call early_ioremap()
before early_ioremap_init.

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

Alexander Kuleshov

unread,
Apr 8, 2015, 5:40:07 AM4/8/15
to
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 provides initialization of earlyprintk serial console as early
as possible in the arch/x86/kerne/head{32,64}.c

Alexander Kuleshov (2):
x86/setup: update boot_command_line with builtin_cmdline in separate
function
x86/earlyprintk: setup earlyprintk as early as possible

arch/x86/kernel/early_printk.c | 2 +-
arch/x86/kernel/head.c | 14 ++++++++++++++
arch/x86/kernel/head32.c | 3 +++
arch/x86/kernel/head64.c | 8 +++++++-
arch/x86/kernel/setup.c | 31 ++++++++++++++++++-------------
include/linux/init.h | 6 +++++-
include/linux/printk.h | 4 ++++
kernel/printk/printk.c | 11 +++++++----
8 files changed, 59 insertions(+), 20 deletions(-)

--
2.3.3.611.g09038fc.dirty

Alexander Kuleshov

unread,
Apr 9, 2015, 4:20:05 AM4/9/15
to
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 makes setup_early_printk visible for head{32,64}.c So 'early_printk'
function will be 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 setup_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.

Signed-off-by: Alexander Kuleshov <kulesh...@gmail.com>
---
arch/x86/include/asm/serial.h | 7 +++++++
arch/x86/kernel/early_printk.c | 31 +++++++++++++++++++++++++++++--
arch/x86/kernel/head32.c | 5 +++++
arch/x86/kernel/head64.c | 9 ++++++++-
4 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/serial.h b/arch/x86/include/asm/serial.h
index 460b84f..789e123 100644
--- a/arch/x86/include/asm/serial.h
+++ b/arch/x86/include/asm/serial.h
@@ -26,4 +26,11 @@
{ .uart = 0, BASE_BAUD, 0x3E8, 4, STD_COMX_FLAGS }, /* ttyS2 */ \
{ .uart = 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */

+
+#ifdef CONFIG_EARLY_PRINTK
+int setup_early_serial_console(void);
+#else
+static void setup_early_serial_console(void) {};
+#endif
+
#endif /* _ASM_X86_SERIAL_H */
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index a62536a..6052eba 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -11,6 +11,7 @@
#include <asm/processor.h>
#include <asm/fcntl.h>
#include <asm/setup.h>
+#include <asm/serial.h>
#include <xen/hvc-console.h>
#include <asm/pci-direct.h>
#include <asm/fixmap.h>
@@ -342,14 +343,16 @@ 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);
}
@@ -391,4 +394,28 @@ static int __init setup_early_printk(char *buf)
return 0;
}

+int setup_early_serial_console() {
+#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 7ad0ad0..c59afe4 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -19,6 +19,7 @@
#include <asm/bios_ebda.h>
#include <asm/tlbflush.h>
#include <asm/bootparam_utils.h>
+#include <asm/serial.h>

static void __init i386_default_early_setup(void)
{
@@ -32,6 +33,10 @@ static void __init i386_default_early_setup(void)
asmlinkage __visible void __init i386_start_kernel(void)
{
setup_cmdline();
+ /* setup serial console as early as possible */
+ setup_early_serial_console();
+ early_printk("Early serial console is active\n");
+
cr4_init_shadow();
sanitize_boot_params(&boot_params);

diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 6eea2de..129acc3 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.
@@ -172,12 +173,16 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)

copy_bootdata(__va(real_mode_data));
setup_cmdline();
+ /* setup serial console as early as possible */
+ setup_early_serial_console();
+ early_printk("Early serial console is active\n");

/*
* Load microcode early on BSP.
*/
load_ucode_bsp();

+
if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG)
early_printk("Kernel alive\n");

@@ -193,8 +198,10 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
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_serial_console();
+ }

reserve_ebda_region();
0 new messages