From: Alexandru Elisei <alexandru.elisei@xxxxxxx> The MMU is now enabled before the UART is probed, which leaves kvm-unit-tests with a window where attempting to write to the console results in an infinite data abort loop triggered by the exception handlers themselves trying to use the console. Get around this by mapping the UART early address when creating the translation tables. Signed-off-by: Alexandru Elisei <alexandru.elisei@xxxxxxx> Signed-off-by: Shaoqin Huang <shahuang@xxxxxxxxxx> --- lib/arm/io.c | 31 +++++++++++++++++++++++++++++++ lib/arm/io.h | 3 +++ lib/arm/mmu.c | 3 +++ 3 files changed, 37 insertions(+) diff --git a/lib/arm/io.c b/lib/arm/io.c index c15e57c4..becd52a5 100644 --- a/lib/arm/io.c +++ b/lib/arm/io.c @@ -15,6 +15,8 @@ #include <asm/psci.h> #include <asm/spinlock.h> #include <asm/io.h> +#include <asm/mmu.h> +#include <asm/thread_info.h> #include "io.h" @@ -29,6 +31,29 @@ static struct spinlock uart_lock; #define UART_EARLY_BASE (u8 *)(unsigned long)CONFIG_UART_EARLY_BASE static volatile u8 *uart0_base = UART_EARLY_BASE; +static void uart_unmap_early_base(void) +{ + pteval_t *ptevalp; + pgd_t *pgtable; + + if (mmu_enabled()) { + pgtable = current_thread_info()->pgtable; + } else { + pgtable = mmu_idmap; + } + + /* + * The UART has been mapped early in the boot process and the PTE has + * been allocated using the physical allocator, which means it cannot be + * freed. + */ + ptevalp = follow_pte(pgtable, (uintptr_t)UART_EARLY_BASE); + if (ptevalp) { + WRITE_ONCE(*ptevalp, 0); + flush_tlb_page((uintptr_t)UART_EARLY_BASE); + } +} + static void uart0_init_fdt(void) { /* @@ -98,11 +123,17 @@ void io_init(void) printf("WARNING: early print support may not work. " "Found uart at %p, but early base is %p.\n", uart0_base, UART_EARLY_BASE); + uart_unmap_early_base(); } chr_testdev_init(); } +void __iomem *uart_early_base(void) +{ + return UART_EARLY_BASE; +} + void puts(const char *s) { spin_lock(&uart_lock); diff --git a/lib/arm/io.h b/lib/arm/io.h index 183479c8..74b2850a 100644 --- a/lib/arm/io.h +++ b/lib/arm/io.h @@ -7,6 +7,9 @@ #ifndef _ARM_IO_H_ #define _ARM_IO_H_ +#include <asm/io.h> + extern void io_init(void); +extern void __iomem *uart_early_base(void); #endif diff --git a/lib/arm/mmu.c b/lib/arm/mmu.c index d23a12e8..0aec0bf9 100644 --- a/lib/arm/mmu.c +++ b/lib/arm/mmu.c @@ -15,6 +15,7 @@ #include <asm/pgtable.h> #include <asm/pgtable-hwdef.h> +#include "io.h" #include "vmalloc.h" #include <linux/compiler.h> @@ -233,6 +234,8 @@ void mmu_setup_early(phys_addr_t phys_end) } } + ioremap((phys_addr_t)(unsigned long)uart_early_base(), PAGE_SIZE); + /* * Open-code part of mmu_enabled(), because at this point thread_info * hasn't been initialized. mmu_mark_enabled() cannot be called here -- 2.40.1