[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v1 1/1] xen/riscv: replace SBI early console with 8250 UART



As noted by the TODO, the legacy SBI console extension is planned
for deprecation. Replace it with direct access to UART MMIO.

Signed-off-by: Zhang Zheng <zhangzheng@xxxxxxxxxxx>
---
 xen/arch/riscv/Kconfig.debug              | 53 ++++++++++++++++++++--
 xen/arch/riscv/configs/tiny64_defconfig   |  2 +
 xen/arch/riscv/early_printk.c             | 37 +++++++---------
 xen/arch/riscv/include/asm/early_printk.h | 12 +++++
 xen/arch/riscv/include/asm/fixmap.h       |  6 ++-
 xen/arch/riscv/include/asm/sbi.h          |  7 ---
 xen/arch/riscv/mm.c                       | 41 +++++++++++++----
 xen/arch/riscv/riscv64/Makefile           |  1 +
 xen/arch/riscv/riscv64/debug-8250.inc     | 51 +++++++++++++++++++++
 xen/arch/riscv/riscv64/debug.S            | 54 +++++++++++++++++++++++
 xen/arch/riscv/sbi.c                      |  5 ---
 11 files changed, 223 insertions(+), 46 deletions(-)
 create mode 100644 xen/arch/riscv/riscv64/debug-8250.inc
 create mode 100644 xen/arch/riscv/riscv64/debug.S

diff --git a/xen/arch/riscv/Kconfig.debug b/xen/arch/riscv/Kconfig.debug
index 608c9ff832..51536e7151 100644
--- a/xen/arch/riscv/Kconfig.debug
+++ b/xen/arch/riscv/Kconfig.debug
@@ -1,5 +1,50 @@
+choice
+       bool "Early printk"
+       optional
+       help
+         You may want to enable early printk if you are debugging code
+         that executes before the console is initialized.
+
+         Note that selecting this option will limit Xen to a single UART
+         definition. Attempting to boot the Xen image on a different
+         platform will not work, so this option should not be enabled
+         for Xen images that are intended to be portable.
+
+         Choose one of the UART drivers for early printk, then specify
+         parameters such as the base address.
+
+       config EARLY_UART_CHOICE_8250
+               select EARLY_UART_8250
+               bool "Early printk via 8250 UART"
+               help
+                 Say Y here if you wish early printk to direct its output
+                 to an already configured 8250-compatible UART.
+
+endchoice
+
+config EARLY_UART_8250
+       select EARLY_PRINTK
+       bool
+
 config EARLY_PRINTK
-    bool "Enable early printk"
-    default DEBUG
-    help
-      Enables early printk debug messages
+       bool
+
+config EARLY_UART_BASE_ADDRESS
+       depends on EARLY_UART_8250
+       hex "Early printk, physical base address of debug UART"
+
+config EARLY_UART_8250_REG_SHIFT
+       depends on EARLY_UART_8250
+       int "Early printk, left-shift to apply to the register offsets within 
the 8250 UART"
+       default 0
+       range 0 4
+       help
+         EARLY_UART_8250_REG_SHIFT is, optionally, the left-shift to
+         apply to the register offsets within the UART with early
+         printk.
+
+         Default to 0.
+
+config EARLY_PRINTK_INC
+       string
+       default "debug-8250.inc" if EARLY_UART_8250
diff --git a/xen/arch/riscv/configs/tiny64_defconfig 
b/xen/arch/riscv/configs/tiny64_defconfig
index 2399f7b918..438db66551 100644
--- a/xen/arch/riscv/configs/tiny64_defconfig
+++ b/xen/arch/riscv/configs/tiny64_defconfig
@@ -10,3 +10,5 @@ CONFIG_DEBUG=y
 CONFIG_DEBUG_INFO=y
 CONFIG_EXPERT=y
 CONFIG_QEMU_PLATFORM=y
+CONFIG_EARLY_UART_CHOICE_8250=y
+CONFIG_EARLY_UART_BASE_ADDRESS=0x10000000
diff --git a/xen/arch/riscv/early_printk.c b/xen/arch/riscv/early_printk.c
index 634141354c..bb2dc6c719 100644
--- a/xen/arch/riscv/early_printk.c
+++ b/xen/arch/riscv/early_printk.c
@@ -1,42 +1,37 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * RISC-V early printk using SBI
+ * RISC-V early printk
  *
  * Copyright (C) 2021 Bobby Eshleman <bobbyeshleman@xxxxxxxxx>
  */
-#include <asm/early_printk.h>
-#include <asm/sbi.h>
+#include <xen/early_printk.h>
 
-/*
- * When the MMU is off during early boot, any C function called has to
- * use PC-relative rather than absolute address because the physical address
- * may not match the virtual address.
- *
- * To guarantee PC-relative address cmodel=medany should be used
- */
 #ifndef __riscv_cmodel_medany
 #error "early_*() can be called from head.S with MMU-off"
 #endif
 
-/*
- * TODO:
- *   sbi_console_putchar is already planned for deprecation
- *   so it should be reworked to use UART directly.
-*/
+void early_putch(char c);
+void early_flush(void);
+
 void early_puts(const char *s, size_t nr)
 {
     while ( nr-- > 0 )
     {
-        sbi_console_putchar(*s);
+        if ( *s == '\n' )
+            early_putch('\r');
+        early_putch(*s);
         s++;
     }
+
+    early_flush();
 }
 
 void early_printk(const char *str)
 {
-    while ( *str )
-    {
-        early_puts(str, 1);
-        str++;
-    }
+    const char *end = str;
+
+    while ( *end )
+        end++;
+
+    early_puts(str, end - str);
 }
diff --git a/xen/arch/riscv/include/asm/early_printk.h 
b/xen/arch/riscv/include/asm/early_printk.h
index 2750045bdd..e4c95ed7b4 100644
--- a/xen/arch/riscv/include/asm/early_printk.h
+++ b/xen/arch/riscv/include/asm/early_printk.h
@@ -3,6 +3,7 @@
 #ifndef ASM__RISCV__EARLY_PRINTK_H
 #define ASM__RISCV__EARLY_PRINTK_H
 
+#ifndef __ASSEMBLER__
 #include <xen/early_printk.h>
 
 #ifdef CONFIG_EARLY_PRINTK
@@ -10,5 +11,16 @@ void early_printk(const char *str);
 #else
 static inline void early_printk(const char *s) {};
 #endif
+#endif
+
+#ifdef CONFIG_EARLY_PRINTK
+
+#include <xen/page-size.h>
+#include <asm/fixmap.h>
+
+/* need to add the uart address offset in page to the fixmap address */
+#define EARLY_UART_VIRTUAL_ADDRESS \
+    (FIXMAP_ADDR(FIX_CONSOLE) + (CONFIG_EARLY_UART_BASE_ADDRESS & ~PAGE_MASK))
+#endif
 
 #endif /* ASM__RISCV__EARLY_PRINTK_H */
diff --git a/xen/arch/riscv/include/asm/fixmap.h 
b/xen/arch/riscv/include/asm/fixmap.h
index 085d135c15..66a78bb19d 100644
--- a/xen/arch/riscv/include/asm/fixmap.h
+++ b/xen/arch/riscv/include/asm/fixmap.h
@@ -17,8 +17,12 @@
 #define FIX_PMAP_BEGIN (0) /* Start of PMAP */
 #define FIX_PMAP_END (FIX_PMAP_BEGIN + NUM_FIX_PMAP - 1) /* End of PMAP */
 #define FIX_MISC (FIX_PMAP_END + 1)  /* Ephemeral mappings of hardware */
-
+#ifdef CONFIG_EARLY_PRINTK
+#define FIX_CONSOLE (FIX_MISC + 1) /* Early UART mapping */
+#define FIX_LAST FIX_CONSOLE
+#else
 #define FIX_LAST FIX_MISC
+#endif
 
 #define FIXADDR_START FIXMAP_ADDR(0)
 #define FIXADDR_TOP FIXMAP_ADDR(FIX_LAST + 1)
diff --git a/xen/arch/riscv/include/asm/sbi.h b/xen/arch/riscv/include/asm/sbi.h
index 1952868e96..d043fc7632 100644
--- a/xen/arch/riscv/include/asm/sbi.h
+++ b/xen/arch/riscv/include/asm/sbi.h
@@ -75,13 +75,6 @@ struct sbiret sbi_ecall(unsigned long ext, unsigned long fid,
                         unsigned long arg2, unsigned long arg3,
                         unsigned long arg4, unsigned long arg5);
 
-/**
- * Writes given character to the console device.
- *
- * @param ch The data to be written to the console.
- */
-void sbi_console_putchar(int ch);
-
 void sbi_shutdown(void);
 
 /*
diff --git a/xen/arch/riscv/mm.c b/xen/arch/riscv/mm.c
index 610d111945..8480e61de2 100644
--- a/xen/arch/riscv/mm.c
+++ b/xen/arch/riscv/mm.c
@@ -76,6 +76,27 @@ stage1_pgtbl_nonroot[PGTBL_INITIAL_COUNT * 
PAGETABLE_ENTRIES];
 pte_t __section(".bss.page_aligned") __aligned(PAGE_SIZE)
 xen_fixmap[PAGETABLE_ENTRIES];
 
+#ifdef CONFIG_EARLY_PRINTK
+static void __init setup_early_uart_mapping(void)
+{
+    pte_t *pgtbl = stage1_pgtbl_root;
+    unsigned int i;
+
+    /* Add UART to the fixmap table. */
+    xen_fixmap[pt_index(0, EARLY_UART_VIRTUAL_ADDRESS)] =
+        paddr_to_pte(CONFIG_EARLY_UART_BASE_ADDRESS & PAGE_MASK,
+                     PAGE_HYPERVISOR_RW);
+
+    for ( i = HYP_PT_ROOT_LEVEL; i > 1; i-- )
+        pgtbl = (pte_t *)pte_to_paddr(
+            pgtbl[pt_index(i, FIXMAP_ADDR(0))]);
+
+    /* Map fixmap into the initial page tables. */
+    pgtbl[pt_index(1, FIXMAP_ADDR(0))] =
+        paddr_to_pte((paddr_t)xen_fixmap, PTE_TABLE);
+}
+#endif
+
 #define HANDLE_PGTBL(curr_lvl_num)                                          \
     index = pt_index(curr_lvl_num, page_addr);                              \
     if ( pte_is_valid(pgtbl[index]) )                                       \
@@ -243,18 +264,18 @@ void __init setup_fixmap_mappings(void)
         pte = &pte[pt_index(i, FIXMAP_ADDR(0))];
     }
 
-    BUG_ON(pte_is_valid(*pte));
-
-    tmp = paddr_to_pte(virt_to_maddr(&xen_fixmap), PTE_TABLE);
-    write_pte(pte, tmp);
+    if ( pte_is_valid(*pte) )
+        BUG_ON(pte_to_paddr(*pte) != virt_to_maddr(xen_fixmap));
+    else
+    {
+        tmp = paddr_to_pte(virt_to_maddr(xen_fixmap), PTE_TABLE);
+        write_pte(pte, tmp);
+    }
 
     RISCV_FENCE(rw, rw);
     sfence_vma();
 
-    /*
-     * We only need the zeroeth table allocated, but not the PTEs set, because
-     * set_fixmap() will set them on the fly.
-     */
+    /* Remaining fixmap entries are populated on demand by set_fixmap(). */
 }
 
 /*
@@ -314,6 +335,10 @@ void __init setup_initial_pagetables(void)
                           linker_end,
                           load_start);
 
+#ifdef CONFIG_EARLY_PRINTK
+    setup_early_uart_mapping();
+#endif
+
     if ( linker_start == load_start )
         return;
 
diff --git a/xen/arch/riscv/riscv64/Makefile b/xen/arch/riscv/riscv64/Makefile
index 3340058c08..a35968ead7 100644
--- a/xen/arch/riscv/riscv64/Makefile
+++ b/xen/arch/riscv/riscv64/Makefile
@@ -1 +1,2 @@
+obj-$(CONFIG_EARLY_PRINTK) += debug.o
 obj-y += head.o
diff --git a/xen/arch/riscv/riscv64/debug-8250.inc 
b/xen/arch/riscv/riscv64/debug-8250.inc
new file mode 100644
index 0000000000..5918e74cbd
--- /dev/null
+++ b/xen/arch/riscv/riscv64/debug-8250.inc
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * xen/arch/riscv/riscv64/debug-8250.inc
+ *
+ * 8250 specific debug code
+ *
+ * Copyright (c) 2013 Applied Micro.
+ * Copyright (c) 2026 Zheng Zhang.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/8250-uart.h>
+
+/*
+ * UART wait UART to be ready to transmit
+ * xb: register which contains the UART base address
+ * c: scratch register
+ */
+.macro early_uart_ready xb c
+1:
+        lbu     \c, (UART_LSR << CONFIG_EARLY_UART_8250_REG_SHIFT)(\xb)
+        andi    \c, \c, UART_LSR_THRE
+        xori    \c, \c, UART_LSR_THRE
+        bnez    \c, 1b
+.endm
+
+/*
+ * UART transmit character
+ * xb: register which contains the UART base address
+ * wt: register which contains the character to transmit
+ */
+.macro early_uart_transmit xb wt
+        /* UART_THR transmit holding */
+        sb      \wt, (UART_THR << CONFIG_EARLY_UART_8250_REG_SHIFT)(\xb)
+.endm
+
+/*
+ * Local variables:
+ * mode: ASM
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/riscv/riscv64/debug.S b/xen/arch/riscv/riscv64/debug.S
new file mode 100644
index 0000000000..4e7465e1d8
--- /dev/null
+++ b/xen/arch/riscv/riscv64/debug.S
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * xen/arch/riscv/riscv64/debug.S
+ *
+ * Wrapper for early printk
+ *
+ * Julien Grall <julien.grall@xxxxxxxxxx>
+ * Copyright (c) 2013 Linaro Limited.
+ * Copyright (c) 2026 Zheng Zhang.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/asm.h>
+#include <asm/early_printk.h>
+#include <asm/riscv_encoding.h>
+
+#include CONFIG_EARLY_PRINTK_INC
+
+.macro early_uart_base bs, c
+        li      \bs, CONFIG_EARLY_UART_BASE_ADDRESS
+        csrr    \c, CSR_SATP
+        beqz    \c, 1f
+        li      \bs, EARLY_UART_VIRTUAL_ADDRESS
+1:
+.endm
+
+/* Print the character in a0. */
+FUNC(early_putch)
+        early_uart_base t0, t1
+        early_uart_ready t0, t1
+        andi    a0, a0, 0xff
+        early_uart_transmit t0, a0
+        ret
+END(early_putch)
+
+/* Wait until both the transmit FIFO and shift register are empty. */
+FUNC(early_flush)
+        early_uart_base t0, t1
+1:
+        lbu     t1, (UART_LSR << CONFIG_EARLY_UART_8250_REG_SHIFT)(t0)
+        andi    t1, t1, (UART_LSR_THRE | UART_LSR_TEMT)
+        xori    t1, t1, (UART_LSR_THRE | UART_LSR_TEMT)
+        bnez    t1, 1b
+        ret
+END(early_flush)
diff --git a/xen/arch/riscv/sbi.c b/xen/arch/riscv/sbi.c
index 3576e26033..bca3ebdca5 100644
--- a/xen/arch/riscv/sbi.c
+++ b/xen/arch/riscv/sbi.c
@@ -72,11 +72,6 @@ static int sbi_err_map_xen_errno(int err)
     };
 }
 
-void sbi_console_putchar(int ch)
-{
-    sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0);
-}
-
 void sbi_shutdown(void)
 {
     sbi_ecall(SBI_EXT_0_1_SHUTDOWN, 0, 0, 0, 0, 0, 0, 0);
-- 
2.54.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.