[kvm-unit-tests PATCH v1 16/18] arm/arm64: Map the UART when creating the translation tables

Shaoqin Huang
2023-11-30T09:08:02Z

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@arm.com>
Signed-off-by: Shaoqin Huang <shahuang@redhat.com>
---
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