diff mbox

[1/2] hvc_xen: add earlycon support

Message ID 1456316590-20020-1-git-send-email-stefano.stabellini@eu.citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Stefano Stabellini Feb. 24, 2016, 12:23 p.m. UTC
Introduce EARLYCON support in hvc_xen, useful for early debugging on arm
and arm64, where xen early_printk is not available. Differently from
xenboot_write_console on x86, we won't just return if !xen_pv_domain(),
because arm and arm64 guests are actually xen_hvm_domain() from linux
pov, and also because we want to capture all possible writes, including
the ones earlier than xen_early_init().

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
 drivers/tty/hvc/hvc_xen.c |   48 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 11 deletions(-)

Comments

Boris Ostrovsky Feb. 24, 2016, 2:43 p.m. UTC | #1
On 02/24/2016 07:23 AM, Stefano Stabellini wrote:
> Introduce EARLYCON support in hvc_xen, useful for early debugging on arm
> and arm64, where xen early_printk is not available. Differently from
> xenboot_write_console on x86, we won't just return if !xen_pv_domain(),
> because arm and arm64 guests are actually xen_hvm_domain() from linux
> pov, and also because we want to capture all possible writes, including
> the ones earlier than xen_early_init().
>
> Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com>
> ---
>   drivers/tty/hvc/hvc_xen.c |   48 ++++++++++++++++++++++++++++++++++-----------
>   1 file changed, 37 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
> index fa816b7..34e8e9f 100644
> --- a/drivers/tty/hvc/hvc_xen.c
> +++ b/drivers/tty/hvc/hvc_xen.c
> @@ -25,6 +25,7 @@
>   #include <linux/init.h>
>   #include <linux/types.h>
>   #include <linux/list.h>
> +#include <linux/serial_core.h>
>   
>   #include <asm/io.h>
>   #include <asm/xen/hypervisor.h>
> @@ -597,21 +598,11 @@ static int xen_cons_init(void)
>   }
>   console_initcall(xen_cons_init);
>   
> -#ifdef CONFIG_EARLY_PRINTK
> -static void xenboot_write_console(struct console *console, const char *string,
> -				  unsigned len)
> +static void domU_write_early_console(const char *string, unsigned len)
>   {
>   	unsigned int linelen, off = 0;
>   	const char *pos;
>   
> -	if (!xen_pv_domain())
> -		return;
> -
> -	dom0_write_console(0, string, len);
> -
> -	if (xen_initial_domain())
> -		return;
> -
>   	domU_write_console(0, "(early) ", 8);
>   	while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
>   		linelen = pos-string+off;
> @@ -625,6 +616,21 @@ static void xenboot_write_console(struct console *console, const char *string,
>   		domU_write_console(0, string+off, len-off);
>   }
>   
> +#ifdef CONFIG_EARLY_PRINTK
> +static void xenboot_write_console(struct console *console, const char *string,
> +				  unsigned len)
> +{
> +	if (!xen_pv_domain())
> +		return;

This, BTW, will break PVHv2 code (which is not there yet). Your patch is 
not making the code any different from what it is now but I wonder 
whether xenboot_write_console() can be made to work for HVM guests at 
this time since you making changes there anyway.

Or we can delay it until HVMlite/PVHv2 patches make it in.

> +
> +	dom0_write_console(0, string, len);
> +
> +	if (xen_initial_domain())
> +		return;
> +
> +	domU_write_early_console(string, len);
> +}
> +
>   struct console xenboot_console = {
>   	.name		= "xenboot",
>   	.write		= xenboot_write_console,
> @@ -664,3 +670,23 @@ void xen_raw_printk(const char *fmt, ...)
>   
>   	xen_raw_console_write(buf);
>   }
> +
> +static void xenboot_earlycon_write(struct console *console,
> +				  const char *string,
> +				  unsigned len)
> +{
> +	dom0_write_console(0, string, len);
> +
> +	if (xen_initial_domain())
> +		return;
> +
> +	domU_write_early_console(string, len);
> +}

xenboot_earlycon_write() and xenboot_write_console() share most of the 
code, can it be factored out?

-boris

> +
> +static int __init xenboot_earlycon_setup(struct earlycon_device *device,
> +					    const char *opt)
> +{
> +	device->con->write = xenboot_earlycon_write;
> +	return 0;
> +}
> +EARLYCON_DECLARE(xenboot, xenboot_earlycon_setup);
Stefano Stabellini Feb. 24, 2016, 3:55 p.m. UTC | #2
On Wed, 24 Feb 2016, Boris Ostrovsky wrote:
> On 02/24/2016 07:23 AM, Stefano Stabellini wrote:
> > Introduce EARLYCON support in hvc_xen, useful for early debugging on arm
> > and arm64, where xen early_printk is not available. Differently from
> > xenboot_write_console on x86, we won't just return if !xen_pv_domain(),
> > because arm and arm64 guests are actually xen_hvm_domain() from linux
> > pov, and also because we want to capture all possible writes, including
> > the ones earlier than xen_early_init().
> > 
> > Signed-off-by: Stefano Stabellini<stefano.stabellini@eu.citrix.com>
> > ---
> >   drivers/tty/hvc/hvc_xen.c |   48
> > ++++++++++++++++++++++++++++++++++-----------
> >   1 file changed, 37 insertions(+), 11 deletions(-)
> > 
> > diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
> > index fa816b7..34e8e9f 100644
> > --- a/drivers/tty/hvc/hvc_xen.c
> > +++ b/drivers/tty/hvc/hvc_xen.c
> > @@ -25,6 +25,7 @@
> >   #include <linux/init.h>
> >   #include <linux/types.h>
> >   #include <linux/list.h>
> > +#include <linux/serial_core.h>
> >     #include <asm/io.h>
> >   #include <asm/xen/hypervisor.h>
> > @@ -597,21 +598,11 @@ static int xen_cons_init(void)
> >   }
> >   console_initcall(xen_cons_init);
> >   -#ifdef CONFIG_EARLY_PRINTK
> > -static void xenboot_write_console(struct console *console, const char
> > *string,
> > -				  unsigned len)
> > +static void domU_write_early_console(const char *string, unsigned len)
> >   {
> >   	unsigned int linelen, off = 0;
> >   	const char *pos;
> >   -	if (!xen_pv_domain())
> > -		return;
> > -
> > -	dom0_write_console(0, string, len);
> > -
> > -	if (xen_initial_domain())
> > -		return;
> > -
> >   	domU_write_console(0, "(early) ", 8);
> >   	while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
> >   		linelen = pos-string+off;
> > @@ -625,6 +616,21 @@ static void xenboot_write_console(struct console
> > *console, const char *string,
> >   		domU_write_console(0, string+off, len-off);
> >   }
> >   +#ifdef CONFIG_EARLY_PRINTK
> > +static void xenboot_write_console(struct console *console, const char
> > *string,
> > +				  unsigned len)
> > +{
> > +	if (!xen_pv_domain())
> > +		return;
> 
> This, BTW, will break PVHv2 code (which is not there yet). Your patch is not
> making the code any different from what it is now but I wonder whether
> xenboot_write_console() can be made to work for HVM guests at this time since
> you making changes there anyway.
> 
> Or we can delay it until HVMlite/PVHv2 patches make it in.

I don't think it can be made to work with HVM guests unfortunately,
because in the HVM case Xen support is going to be discovered only at
some later point. We have the same problem on ARM, where all guests are
xen_hvm_domain(). In that case I solved the problem by calling
dom0_write_console unconditionally from xenboot_earlycon_write, see
below.

I could do the same here by dropping the if (!xen_pv_domain()) check
above, but then if somebody specifies earlyprintk=xenboot on a non-Xen
environment, I expect Linux would crash.


> > +
> > +	dom0_write_console(0, string, len);
> > +
> > +	if (xen_initial_domain())
> > +		return;
> > +
> > +	domU_write_early_console(string, len);
> > +}
> > +
> >   struct console xenboot_console = {
> >   	.name		= "xenboot",
> >   	.write		= xenboot_write_console,
> > @@ -664,3 +670,23 @@ void xen_raw_printk(const char *fmt, ...)
> >     	xen_raw_console_write(buf);
> >   }
> > +
> > +static void xenboot_earlycon_write(struct console *console,
> > +				  const char *string,
> > +				  unsigned len)
> > +{
> > +	dom0_write_console(0, string, len);
> > +
> > +	if (xen_initial_domain())
> > +		return;
> > +
> > +	domU_write_early_console(string, len);
> > +}

My explanation above made me realize that actually
domU_write_early_console can never be called here, so I'll drop it in
the next version.


> xenboot_earlycon_write() and xenboot_write_console() share most of the code,
> can it be factored out?

No, they are actually different. I don't think it would be better to
introduce #ifdef CONFIG_X86 in this file.


> > +
> > +static int __init xenboot_earlycon_setup(struct earlycon_device *device,
> > +					    const char *opt)
> > +{
> > +	device->con->write = xenboot_earlycon_write;
> > +	return 0;
> > +}
> > +EARLYCON_DECLARE(xenboot, xenboot_earlycon_setup);
>
Konrad Rzeszutek Wilk Feb. 24, 2016, 5:18 p.m. UTC | #3
> I could do the same here by dropping the if (!xen_pv_domain()) check
> above, but then if somebody specifies earlyprintk=xenboot on a non-Xen
> environment, I expect Linux would crash.

Nah, you made it "Work" with:
commit eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55
Author: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Date:   Fri Jan 27 18:31:36 2012 +0000

    hvc_xen: support PV on HVM consoles

But this patch:

commit 04b772d2b819f0dda2163e3193fa7cd447a6245c

xen/hvc: If we use xen_raw_printk let it also work on HVM guests.
    
    The xen_raw_printk works great for debugging purposes. We use
    for PV guests and we can also use it for HVM guests.
    
    However, for HVM guests we have a fallback of using the 0xe9
    port in case the hypervisor does not support an HVM guest of
    using the console_io hypercall. As such lets use 0xe9 during
    early bootup, and once the hyper-page is setup and if the
    console_io hypercall is supported - use that. Otherwise we
    will fallback to using the 0xe9 after early bootup.
    
    We also alter the return value for dom0_write_console to return
    an error value instead of zero. The HVC API has been supporting
    returning error values for quite some time.
    
    P.S.
    To use (and to see the output in the Xen ring buffer) one has to build
    the hypervisor with 'debug=y'.

Should make it possible for HVM guests to actually work with HVM x86 guests
if tweaked.
Andrew Cooper Feb. 24, 2016, 5:22 p.m. UTC | #4
On 24/02/16 17:18, Konrad Rzeszutek Wilk wrote:
>> I could do the same here by dropping the if (!xen_pv_domain()) check
>> above, but then if somebody specifies earlyprintk=xenboot on a non-Xen
>> environment, I expect Linux would crash.
> Nah, you made it "Work" with:
> commit eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55
> Author: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> Date:   Fri Jan 27 18:31:36 2012 +0000
>
>     hvc_xen: support PV on HVM consoles
>
> But this patch:
>
> commit 04b772d2b819f0dda2163e3193fa7cd447a6245c
>
> xen/hvc: If we use xen_raw_printk let it also work on HVM guests.
>     
>     The xen_raw_printk works great for debugging purposes. We use
>     for PV guests and we can also use it for HVM guests.
>     
>     However, for HVM guests we have a fallback of using the 0xe9
>     port in case the hypervisor does not support an HVM guest of
>     using the console_io hypercall. As such lets use 0xe9 during
>     early bootup, and once the hyper-page is setup and if the
>     console_io hypercall is supported - use that. Otherwise we
>     will fallback to using the 0xe9 after early bootup.
>     
>     We also alter the return value for dom0_write_console to return
>     an error value instead of zero. The HVC API has been supporting
>     returning error values for quite some time.
>     
>     P.S.
>     To use (and to see the output in the Xen ring buffer) one has to build
>     the hypervisor with 'debug=y'.
>
> Should make it possible for HVM guests to actually work with HVM x86 guests
> if tweaked.

/me looks

+outb_print:
+               for (i = 0; i < len; i++)
+                       outb(str[i], 0xe9);
+#endif

You already have the length to hand.  Use outsb instead, for
substantially fewer vmexits.

~Andrew
Stefano Stabellini Feb. 25, 2016, 11:53 a.m. UTC | #5
On Wed, 24 Feb 2016, Konrad Rzeszutek Wilk wrote:
> > I could do the same here by dropping the if (!xen_pv_domain()) check
> > above, but then if somebody specifies earlyprintk=xenboot on a non-Xen
> > environment, I expect Linux would crash.
> 
> Nah, you made it "Work" with:
> commit eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55
> Author: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> Date:   Fri Jan 27 18:31:36 2012 +0000
> 
>     hvc_xen: support PV on HVM consoles
> 
> But this patch:
> 
> commit 04b772d2b819f0dda2163e3193fa7cd447a6245c
> 
> xen/hvc: If we use xen_raw_printk let it also work on HVM guests.
>     
>     The xen_raw_printk works great for debugging purposes. We use
>     for PV guests and we can also use it for HVM guests.
>     
>     However, for HVM guests we have a fallback of using the 0xe9
>     port in case the hypervisor does not support an HVM guest of
>     using the console_io hypercall. As such lets use 0xe9 during
>     early bootup, and once the hyper-page is setup and if the
>     console_io hypercall is supported - use that. Otherwise we
>     will fallback to using the 0xe9 after early bootup.
>     
>     We also alter the return value for dom0_write_console to return
>     an error value instead of zero. The HVC API has been supporting
>     returning error values for quite some time.
>     
>     P.S.
>     To use (and to see the output in the Xen ring buffer) one has to build
>     the hypervisor with 'debug=y'.
> 
> Should make it possible for HVM guests to actually work with HVM x86 guests
> if tweaked.

That only makes xen_raw_printk and xen_raw_console_write work with HVM
x86 guests, not the generic early_printk calls, usually enabled in PV
guests with "earlyprintk=xen" on the kernel command line.

But the xen_cpuid_base() check and outbs could be used in
xenboot_write_console too to make early_printk work. I'll add a patch
for that.
Stefano Stabellini Feb. 25, 2016, noon UTC | #6
On Wed, 24 Feb 2016, Andrew Cooper wrote:
> On 24/02/16 17:18, Konrad Rzeszutek Wilk wrote:
> >> I could do the same here by dropping the if (!xen_pv_domain()) check
> >> above, but then if somebody specifies earlyprintk=xenboot on a non-Xen
> >> environment, I expect Linux would crash.
> > Nah, you made it "Work" with:
> > commit eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55
> > Author: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > Date:   Fri Jan 27 18:31:36 2012 +0000
> >
> >     hvc_xen: support PV on HVM consoles
> >
> > But this patch:
> >
> > commit 04b772d2b819f0dda2163e3193fa7cd447a6245c
> >
> > xen/hvc: If we use xen_raw_printk let it also work on HVM guests.
> >     
> >     The xen_raw_printk works great for debugging purposes. We use
> >     for PV guests and we can also use it for HVM guests.
> >     
> >     However, for HVM guests we have a fallback of using the 0xe9
> >     port in case the hypervisor does not support an HVM guest of
> >     using the console_io hypercall. As such lets use 0xe9 during
> >     early bootup, and once the hyper-page is setup and if the
> >     console_io hypercall is supported - use that. Otherwise we
> >     will fallback to using the 0xe9 after early bootup.
> >     
> >     We also alter the return value for dom0_write_console to return
> >     an error value instead of zero. The HVC API has been supporting
> >     returning error values for quite some time.
> >     
> >     P.S.
> >     To use (and to see the output in the Xen ring buffer) one has to build
> >     the hypervisor with 'debug=y'.
> >
> > Should make it possible for HVM guests to actually work with HVM x86 guests
> > if tweaked.
> 
> /me looks
> 
> +outb_print:
> +               for (i = 0; i < len; i++)
> +                       outb(str[i], 0xe9);
> +#endif
> 
> You already have the length to hand.  Use outsb instead, for
> substantially fewer vmexits.

I'll take the opportunity to make that change as well
diff mbox

Patch

diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index fa816b7..34e8e9f 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -25,6 +25,7 @@ 
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/serial_core.h>
 
 #include <asm/io.h>
 #include <asm/xen/hypervisor.h>
@@ -597,21 +598,11 @@  static int xen_cons_init(void)
 }
 console_initcall(xen_cons_init);
 
-#ifdef CONFIG_EARLY_PRINTK
-static void xenboot_write_console(struct console *console, const char *string,
-				  unsigned len)
+static void domU_write_early_console(const char *string, unsigned len)
 {
 	unsigned int linelen, off = 0;
 	const char *pos;
 
-	if (!xen_pv_domain())
-		return;
-
-	dom0_write_console(0, string, len);
-
-	if (xen_initial_domain())
-		return;
-
 	domU_write_console(0, "(early) ", 8);
 	while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
 		linelen = pos-string+off;
@@ -625,6 +616,21 @@  static void xenboot_write_console(struct console *console, const char *string,
 		domU_write_console(0, string+off, len-off);
 }
 
+#ifdef CONFIG_EARLY_PRINTK
+static void xenboot_write_console(struct console *console, const char *string,
+				  unsigned len)
+{
+	if (!xen_pv_domain())
+		return;
+
+	dom0_write_console(0, string, len);
+
+	if (xen_initial_domain())
+		return;
+
+	domU_write_early_console(string, len);
+}
+
 struct console xenboot_console = {
 	.name		= "xenboot",
 	.write		= xenboot_write_console,
@@ -664,3 +670,23 @@  void xen_raw_printk(const char *fmt, ...)
 
 	xen_raw_console_write(buf);
 }
+
+static void xenboot_earlycon_write(struct console *console,
+				  const char *string,
+				  unsigned len)
+{
+	dom0_write_console(0, string, len);
+
+	if (xen_initial_domain())
+		return;
+
+	domU_write_early_console(string, len);
+}
+
+static int __init xenboot_earlycon_setup(struct earlycon_device *device,
+					    const char *opt)
+{
+	device->con->write = xenboot_earlycon_write;
+	return 0;
+}
+EARLYCON_DECLARE(xenboot, xenboot_earlycon_setup);