new file mode 100644
@@ -0,0 +1,14 @@
+How to enable early printk
+
+Early printk can only be enabled if debug=y. You may want to enable it if
+you are debbuging code that executes before the console is initialized.
+
+Note that selecting this option will limit Xen to a single UART definition.
+Attempting to boot Xen image on a different platform *will not work*, so this
+option should not be enable for Xens that are intended to be portable.
+
+CONFIG_EARLY_PRINTK=mach
+where mach is the name of the machine:
+ - vexpress: printk with pl011 for versatile express
+
+By default early printk is disabled.
@@ -2,7 +2,7 @@ subdir-$(arm32) += arm32
subdir-$(arm64) += arm64
subdir-y += platforms
-obj-y += early_printk.o
+obj-$(EARLY_PRINTK) += early_printk.o
obj-y += cpu.o
obj-y += domain.o
obj-y += psci.o
@@ -36,3 +36,21 @@ endif
ifneq ($(call cc-option,$(CC),-fvisibility=hidden,n),n)
CFLAGS += -DGCC_HAS_VISIBILITY_ATTRIBUTE
endif
+
+EARLY_PRINTK := n
+
+ifeq ($(debug),y)
+
+# Early printk for versatile express
+# TODO handle UART base address from make command line
+ifeq ($(CONFIG_EARLY_PRINTK), vexpress)
+EARLY_PRINTK_INC := pl011
+endif
+
+ifneq ($(EARLY_PRINTK_INC),)
+EARLY_PRINTK := y
+endif
+
+CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK
+CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK_INC=\"debug-$(EARLY_PRINTK_INC).inc\"
+endif
@@ -5,4 +5,6 @@ obj-y += mode_switch.o
obj-y += proc-ca15.o
obj-y += traps.o
-obj-y += domain.o
\ No newline at end of file
+obj-y += domain.o
+
+obj-$(EARLY_PRINTK) += debug.o
new file mode 100644
@@ -0,0 +1,58 @@
+/*
+ * xen/arch/arm/arm32/debug-pl011.inc
+ *
+ * PL011 specific debug code
+ *
+ * Copyright (c) 2013 Citrix Systems.
+ *
+ * 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.
+ */
+
+#define EARLY_UART_BASE_ADDRESS 0x1c090000
+
+/* PL011 UART initialization
+ * rb: register which contains the UART base address
+ * rc: scratch register 1
+ * rd: scratch register 2 (unused here) */
+.macro early_uart_init rb, rc, rd
+ mov \rc, #0x0
+ str \rc, [\rb, #0x28] /* -> UARTFBRD (Baud divisor fraction) */
+ mov \rc, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */
+ str \rc, [\rb, #0x24] /* -> UARTIBRD (Baud divisor integer) */
+ mov \rc, #0x60 /* 8n1 */
+ str \rc, [\rb, #0x2C] /* -> UARTLCR_H (Line control) */
+ ldr \rc, =0x00000301 /* RXE | TXE | UARTEN */
+ str \rc, [\rb, #0x30] /* -> UARTCR (Control Register) */
+.endm
+
+/* PL011 UART wait UART to be ready to transmit
+ * rb: register which contains the UART base address
+ * rc: scratch register */
+.macro early_uart_ready rb, rc
+1:
+ ldr \rc, [\rb, #0x18] /* <- UARTFR (Flag register) */
+ tst \rc, #0x8 /* Check BUSY bit */
+ bne 1b /* Wait for the UART to be ready */
+.endm
+
+/* PL011 UART transmit character
+ * rb: register which contains the UART base address
+ * rt: register which contains the character to transmit */
+.macro early_uart_transmit rb, rt
+ str \rt, [\rb] /* -> UARTDR (Data Register) */
+.endm
+
+/*
+ * Local variables:
+ * mode: ASM
+ * indent-tabs-mode: nil
+ * End:
+ */
new file mode 100644
@@ -0,0 +1,33 @@
+/*
+ * xen/arch/arm/arm32/debug.S
+ *
+ * Wrapper for early printk
+ *
+ * Julien Grall <julien.grall@linaro.org>
+ * Copyright (c) 2013 Linaro Limited.
+ *
+ * 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/config.h>
+
+#ifdef EARLY_PRINTK_INC
+#include EARLY_PRINTK_INC
+#endif
+
+.globl early_putch
+/* Print a character on the UART - this function is called by C
+ * r0: character to print */
+early_putch:
+ ldr r1, =FIXMAP_ADDR(FIXMAP_CONSOLE) /* r1 := VA UART base address */
+ early_uart_ready r1, r2
+ early_uart_transmit r1, r0
+ mov pc, lr
@@ -32,9 +32,13 @@
#define PT_UPPER(x) (PT_##x & 0xf00)
#define PT_LOWER(x) (PT_##x & 0x0ff)
+#if (defined (EARLY_PRINTK)) && (defined (EARLY_PRINTK_INC))
+#include EARLY_PRINTK_INC
+#endif
+
/* Macro to print a string to the UART, if there is one.
* Clobbers r0-r3. */
-#ifdef EARLY_UART_ADDRESS
+#ifdef EARLY_PRINTK
#define PRINT(_s) \
adr r0, 98f ; \
bl puts ; \
@@ -42,9 +46,9 @@
98: .asciz _s ; \
.align 2 ; \
99:
-#else
+#else /* EARLY_PRINTK */
#define PRINT(s)
-#endif
+#endif /* !EARLY_PRINTK */
.arm
@@ -106,8 +110,8 @@ past_zImage:
bne 1b
boot_cpu:
-#ifdef EARLY_UART_ADDRESS
- ldr r11, =EARLY_UART_ADDRESS /* r11 := UART base address */
+#ifdef EARLY_PRINTK
+ ldr r11, =EARLY_UART_BASE_ADDRESS /* r11 := UART base address */
teq r12, #0 /* CPU 0 sets up the UART too */
bleq init_uart
PRINT("- CPU ")
@@ -216,7 +220,7 @@ skip_bss:
bne pt_ready
/* console fixmap */
-#ifdef EARLY_UART_ADDRESS
+#if defined(EARLY_PRINTK)
ldr r1, =xen_fixmap
add r1, r1, r10 /* r1 := paddr (xen_fixmap) */
mov r3, #0
@@ -279,7 +283,7 @@ pt_ready:
paging:
-#ifdef EARLY_UART_ADDRESS
+#ifdef EARLY_PRINTK
/* Use a virtual address to access the UART. */
ldr r11, =FIXMAP_ADDR(FIXMAP_CONSOLE)
#endif
@@ -345,49 +349,42 @@ fail: PRINT("- Boot failed -\r\n")
1: wfe
b 1b
-#ifdef EARLY_UART_ADDRESS
-/* Bring up the UART. Specific to the PL011 UART.
+#ifdef EARLY_PRINTK
+/* Bring up the UART.
+ * r11: Early UART base address
* Clobbers r0-r2 */
init_uart:
- mov r1, #0x0
- str r1, [r11, #0x28] /* -> UARTFBRD (Baud divisor fraction) */
- mov r1, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */
- str r1, [r11, #0x24] /* -> UARTIBRD (Baud divisor integer) */
- mov r1, #0x60 /* 8n1 */
- str r1, [r11, #0x2C] /* -> UARTLCR_H (Line control) */
- ldr r1, =0x00000301 /* RXE | TXE | UARTEN */
- str r1, [r11, #0x30] /* -> UARTCR (Control Register) */
+ early_uart_init r11, r1, r2
adr r0, 1f
- b puts
+ b puts /* Jump to puts */
1: .asciz "- UART enabled -\r\n"
.align 4
-/* Print early debug messages. Specific to the PL011 UART.
+/* Print early debug messages.
* r0: Nul-terminated string to print.
- * Clobbers r0-r2 */
+ * r11: Early UART base address
+ * Clobbers r0-r1 */
puts:
- ldr r2, [r11, #0x18] /* <- UARTFR (Flag register) */
- tst r2, #0x8 /* Check BUSY bit */
- bne puts /* Wait for the UART to be ready */
- ldrb r2, [r0], #1 /* Load next char */
- teq r2, #0 /* Exit on nul */
+ early_uart_ready r11, r1
+ ldrb r1, [r0], #1 /* Load next char */
+ teq r1, #0 /* Exit on nul */
moveq pc, lr
- str r2, [r11] /* -> UARTDR (Data Register) */
- b puts
+ early_uart_transmit r11, r1
+ b puts
/* Print a 32-bit number in hex. Specific to the PL011 UART.
* r0: Number to print.
- * clobbers r0-r3 */
+ * r11: Early UART base address
+ * Clobbers r0-r3 */
putn:
adr r1, hex
mov r3, #8
-1: ldr r2, [r11, #0x18] /* <- UARTFR (Flag register) */
- tst r2, #0x8 /* Check BUSY bit */
- bne 1b /* Wait for the UART to be ready */
+1:
+ early_uart_ready r11, r2
and r2, r0, #0xf0000000 /* Mask off the top nybble */
ldrb r2, [r1, r2, lsr #28] /* Convert to a char */
- str r2, [r11] /* -> UARTDR (Data Register) */
+ early_uart_transmit r11, r2
lsl r0, #4 /* Roll it through one nybble at a time */
subs r3, r3, #1
bne 1b
@@ -396,7 +393,7 @@ putn:
hex: .ascii "0123456789abcdef"
.align 2
-#else /* EARLY_UART_ADDRESS */
+#else /* EARLY_PRINTK */
init_uart:
.global early_puts
@@ -404,7 +401,7 @@ early_puts:
puts:
putn: mov pc, lr
-#endif /* EARLY_UART_ADDRESS */
+#endif /* !EARLY_PRINTK */
/*
* Local variables:
@@ -5,3 +5,5 @@ obj-y += mode_switch.o
obj-y += traps.o
obj-y += domain.o
+
+obj-$(EARLY_PRINTK) += debug.o
new file mode 100644
@@ -0,0 +1,59 @@
+/*
+ * xen/arch/arm/arm64/debug-pl011.S
+ *
+ * PL011 specific debug code
+ *
+ * Copyright (c) 2013 Citrix Systems.
+ *
+ * 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_defns.h>
+
+#define EARLY_UART_BASE_ADDRESS 0x1c090000
+
+/* PL011 UART initialization
+ * xb: register which containts the UART base address
+ * c: scratch register number */
+.macro early_uart_init xb, c
+ mov x\c, #0x0
+ strh w\c, [\xb, #0x28] /* -> UARTFBRD (Baud divisor fraction) */
+ mov x\c, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */
+ strh w\c, [\xb, #0x24] /* -> UARTIBRD (Baud divisor integer) */
+ mov x\c, #0x60 /* 8n1 */
+ str w\c, [\xb, #0x2C] /* -> UARTLCR_H (Line control) */
+ ldr x\c, =0x00000301 /* RXE | TXE | UARTEN */
+ str w\c, [\xb, #0x30] /* -> UARTCR (Control Register) */
+.endm
+
+/* PL011 UART wait UART to be ready to transmit
+ * xb: register which contains the UART base address
+ * c: scratch register number */
+.macro early_uart_ready xb, c
+1:
+ ldrh w\c, [\xb, #0x18] /* <- UARTFR (Flag register) */
+ tst w\c, #0x8 /* Check BUSY bit */
+ b.ne 1b /* Wait for the UART to be ready */
+.endm
+
+/* PL011 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
+ strb \wt, [\xb] /* -> UARTDR (Data Register) */
+.endm
+
+/*
+ * Local variables:
+ * mode: ASM
+ * indent-tabs-mode: nil
+ * End:
+ */
new file mode 100644
@@ -0,0 +1,33 @@
+/*
+ * xen/arch/arm/arm64/debug.S
+ *
+ * Wrapper for early printk
+ *
+ * Julien Grall <julien.grall@linaro.org>
+ * Copyright (c) 2013 Linaro Limited.
+ *
+ * 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/config.h>
+
+#ifdef EARLY_PRINTK_INC
+#include EARLY_PRINTK_INC
+#endif
+
+.globl early_putch
+/* Print a character on the UART - this function is called by C
+ * x0: character to print */
+early_putch:
+ ldr x23, =FIXMAP_ADDR(FIXMAP_CONSOLE)
+ early_uart_ready x23, 1
+ early_uart_transmit x23, w0
+ ret
@@ -29,9 +29,13 @@
#define PT_DEV 0xe71 /* nG=1 AF=1 SH=10 AP=01 NS=1 ATTR=100 T=0 P=1 */
#define PT_DEV_L3 0xe73 /* nG=1 AF=1 SH=10 AP=01 NS=1 ATTR=100 T=1 P=1 */
+#if (defined (EARLY_PRINTK)) && (defined (EARLY_PRINTK_INC))
+#include EARLY_PRINTK_INC
+#endif
+
/* Macro to print a string to the UART, if there is one.
- * Clobbers r0-r3. */
-#ifdef EARLY_UART_ADDRESS
+ * Clobbers x0-x3. */
+#ifdef EARLY_PRINTK
#define PRINT(_s) \
adr x0, 98f ; \
bl puts ; \
@@ -39,9 +43,9 @@
98: .asciz _s ; \
.align 2 ; \
99:
-#else
+#else /* EARLY_PRINTK */
#define PRINT(s)
-#endif
+#endif /* !EARLY_PRINTK */
/*.aarch64*/
@@ -109,8 +113,8 @@ real_start:
2:
boot_cpu:
-#ifdef EARLY_UART_ADDRESS
- ldr x23, =EARLY_UART_ADDRESS /* x23 := UART base address */
+#ifdef EARLY_PRINTK
+ ldr x23, =EARLY_UART_BASE_ADDRESS /* x23 := UART base address */
cbnz x22, 1f
bl init_uart /* CPU 0 sets up the UART too */
1: PRINT("- CPU ")
@@ -206,7 +210,6 @@ skip_bss:
mov x4, x1 /* Next level into xen_first */
/* console fixmap */
-#ifdef EARLY_UART_ADDRESS
ldr x1, =xen_fixmap
add x1, x1, x20 /* x1 := paddr (xen_fixmap) */
lsr x2, x23, #12
@@ -214,7 +217,6 @@ skip_bss:
mov x3, #PT_DEV_L3
orr x2, x2, x3 /* x2 := 4K dev map including UART */
str x2, [x1, #(FIXMAP_CONSOLE*8)] /* Map it in the first fixmap's slot */
-#endif
/* Build the baseline idle pagetable's first-level entries */
ldr x1, =xen_second
@@ -266,10 +268,8 @@ pt_ready:
br x1 /* Get a proper vaddr into PC */
paging:
-#ifdef EARLY_UART_ADDRESS
/* Use a virtual address to access the UART. */
ldr x23, =FIXMAP_ADDR(FIXMAP_CONSOLE)
-#endif
PRINT("- Ready -\r\n")
@@ -329,51 +329,44 @@ fail: PRINT("- Boot failed -\r\n")
1: wfe
b 1b
-#ifdef EARLY_UART_ADDRESS
+#ifdef EARLY_PRINTK
-/* Bring up the UART. Specific to the PL011 UART.
- * Clobbers r0-r2 */
+/* Bring up the UART.
+ * x23: Early UART base address
+ * Clobbers x0-x1 */
init_uart:
- mov x1, #0x0
- strh w1, [x23, #0x24] /* -> UARTIBRD (Baud divisor fraction) */
- mov x1, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */
- strh w1, [x23, #0x24] /* -> UARTIBRD (Baud divisor integer) */
- mov x1, #0x60 /* 8n1 */
- strh w1, [x23, #0x24] /* -> UARTLCR_H (Line control) */
- ldr x1, =0x00000301 /* RXE | TXE | UARTEN */
- strh w1, [x23, #0x30] /* -> UARTCR (Control Register) */
+ early_uart_init x23, 0
adr x0, 1f
b puts
1: .asciz "- UART enabled -\r\n"
.align 4
-/* Print early debug messages. Specific to the PL011 UART.
- * r0: Nul-terminated string to print.
- * Clobbers r0-r2 */
+/* Print early debug messages.
+ * x0: Nul-terminated string to print.
+ * x23: Early UART base address
+ * Clobbers x0-x1 */
puts:
- ldrh w2, [x23, #0x18] /* <- UARTFR (Flag register) */
- tst w2, #0x8 /* Check BUSY bit */
- b.ne puts /* Wait for the UART to be ready */
- ldrb w2, [x0], #1 /* Load next char */
- cbz w2, 1f /* Exit on nul */
- str w2, [x23] /* -> UARTDR (Data Register) */
+ early_uart_ready x23, 1
+ ldrb w1, [x0], #1 /* Load next char */
+ cbz w1, 1f /* Exit on nul */
+ early_uart_transmit x23, w1
b puts
1:
ret
/* Print a 32-bit number in hex. Specific to the PL011 UART.
- * r0: Number to print.
- * clobbers r0-r3 */
+ * x0: Number to print.
+ * x23: Early UART base address
+ * Clobbers x0-x3 */
putn:
adr x1, hex
mov x3, #8
-1: ldrh w2, [x23, #0x18] /* <- UARTFR (Flag register) */
- tst w2, #0x8 /* Check BUSY bit */
- b.ne 1b /* Wait for the UART to be ready */
+1:
+ early_uart_ready x23, 2
and x2, x0, #0xf0000000 /* Mask off the top nybble */
lsr x2, x2, #28
ldrb w2, [x1, x2] /* Convert to a char */
- strb w2, [x23] /* -> UARTDR (Data Register) */
+ early_uart_transmit x23, w2
lsl x0, x0, #4 /* Roll it through one nybble at a time */
subs x3, x3, #1
b.ne 1b
@@ -382,7 +375,7 @@ putn:
hex: .ascii "0123456789abcdef"
.align 2
-#else /* EARLY_UART_ADDRESS */
+#else /* EARLY_PRINTK */
init_uart:
.global early_puts
@@ -390,4 +383,4 @@ early_puts:
puts:
putn: ret
-#endif /* EARLY_UART_ADDRESS */
+#endif /* EARLY_PRINTK */
@@ -15,19 +15,7 @@
#include <xen/string.h>
#include <asm/early_printk.h>
-#ifdef EARLY_UART_ADDRESS
-
-void __init early_putch(char c)
-{
- volatile uint32_t *r;
-
- r = (uint32_t *)(XEN_VIRT_START + (1 << 21));
-
- /* XXX: assuming a PL011 UART. */
- while(*(r + 0x6) & 0x8)
- ;
- *r = c;
-}
+void early_putch(char c);
/* Early printk buffer */
static char __initdata buf[512];
@@ -68,5 +56,3 @@ early_panic(const char *fmt, ...)
while(1);
}
-
-#endif /* #ifdef EARLY_UART_ADDRESS */
@@ -141,8 +141,6 @@ extern unsigned long frametable_virt_end;
#define watchdog_disable() ((void)0)
#define watchdog_enable() ((void)0)
-/* Board-specific: base address of PL011 UART */
-#define EARLY_UART_ADDRESS 0x1c090000
/* Board-specific: base address of GIC + its regs */
#define GIC_BASE_ADDRESS 0x2c000000
#define GIC_DR_OFFSET 0x1000
@@ -14,7 +14,7 @@
#include <xen/init.h>
#include <xen/stdarg.h>
-#ifdef EARLY_UART_ADDRESS
+#ifdef EARLY_PRINTK
void __init early_vprintk(const char *fmt, va_list args);
void early_printk(const char *fmt, ...);
Add CONFIG_EARLY_PRINTK options in configs/arm{32,64}.mk to let the user to choose if he wants to have early output, ie before the console is initialized. This code is specific for each UART. When CONFIG_EARLY_PRINTK is enabled, Xen will only be able to run on a board with this UART. If a developper wants to add support for a new UART, he must implement the following assembly macro/define: - EALY_UART_BASE_ADDRESS: variable which contains the physical base address for the UART - early_uart_init: initialize the UART - early_uart_ready: check and wait until the UART can transmit a new character - early_uart_transmit: transmit a character For more details about the parameters of each function, see arm{32,64}/debug-pl011.inc comments. Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v3: - Fix clobbers list in UART functions - Remove obj-$(CONFIG_EARLY_PL011) in arm32/Makefile. Was unused. - Set EARLY_PRINTK to y only if EARLY_DEBUG_INC is not null. Will avoid redundant line per early printk machine Changes in v2: - Use macro instead of function for assembly early printk API - Add documentation for ARM early printk --- docs/misc/arm/early-printk.txt | 14 ++++++++ xen/arch/arm/Makefile | 2 +- xen/arch/arm/Rules.mk | 18 ++++++++++ xen/arch/arm/arm32/Makefile | 4 ++- xen/arch/arm/arm32/debug-pl011.inc | 58 ++++++++++++++++++++++++++++++ xen/arch/arm/arm32/debug.S | 33 +++++++++++++++++ xen/arch/arm/arm32/head.S | 65 ++++++++++++++++----------------- xen/arch/arm/arm64/Makefile | 2 ++ xen/arch/arm/arm64/debug-pl011.inc | 59 ++++++++++++++++++++++++++++++ xen/arch/arm/arm64/debug.S | 33 +++++++++++++++++ xen/arch/arm/arm64/head.S | 69 ++++++++++++++++-------------------- xen/arch/arm/early_printk.c | 16 +-------- xen/include/asm-arm/config.h | 2 -- xen/include/asm-arm/early_printk.h | 2 +- 14 files changed, 285 insertions(+), 92 deletions(-) create mode 100644 docs/misc/arm/early-printk.txt create mode 100644 xen/arch/arm/arm32/debug-pl011.inc create mode 100644 xen/arch/arm/arm32/debug.S create mode 100644 xen/arch/arm/arm64/debug-pl011.inc create mode 100644 xen/arch/arm/arm64/debug.S