From b21ae4963d0d204a1405c4aedd76eb01cd79dfdd Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Mon, 19 Sep 2022 13:35:54 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Add serial framework for pKVM Debugging a hypervisor tends to be trickier than normal system code such as the kernel. The lack of availability of a UART framework is a significant contributor to that. In order to address this, introduce a framework allowing to load serial drivers into the hypervisor. Bug: 244543039 Bug: 244373730 Change-Id: I2e7a1fd9abc9d5aa9d95f1d271a997d54a8fd582 Signed-off-by: Quentin Perret --- arch/arm64/include/asm/kvm_pkvm_module.h | 1 + arch/arm64/kvm/hyp/include/nvhe/serial.h | 11 ++++ arch/arm64/kvm/hyp/nvhe/Makefile | 3 +- arch/arm64/kvm/hyp/nvhe/modules.c | 2 + arch/arm64/kvm/hyp/nvhe/serial.c | 68 ++++++++++++++++++++++++ arch/arm64/kvm/hyp/nvhe/setup.c | 1 + 6 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/kvm/hyp/include/nvhe/serial.h create mode 100644 arch/arm64/kvm/hyp/nvhe/serial.c diff --git a/arch/arm64/include/asm/kvm_pkvm_module.h b/arch/arm64/include/asm/kvm_pkvm_module.h index 8b45704529e7..27bc000132c3 100644 --- a/arch/arm64/include/asm/kvm_pkvm_module.h +++ b/arch/arm64/include/asm/kvm_pkvm_module.h @@ -10,6 +10,7 @@ struct pkvm_module_ops { int (*create_private_mapping)(phys_addr_t phys, size_t size, enum kvm_pgtable_prot prot, unsigned long *haddr); + int (*register_serial_driver)(void (*hyp_putc_cb)(char)); }; struct pkvm_module_section { diff --git a/arch/arm64/kvm/hyp/include/nvhe/serial.h b/arch/arm64/kvm/hyp/include/nvhe/serial.h new file mode 100644 index 000000000000..85ff8fdd6c9c --- /dev/null +++ b/arch/arm64/kvm/hyp/include/nvhe/serial.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ARM64_KVM_NVHE_SERIAL_H__ +#define __ARM64_KVM_NVHE_SERIAL_H__ + +void hyp_puts(const char *s); +void hyp_putx64(u64 x); +void hyp_putc(char c); +int __pkvm_register_serial_driver(void (*driver_cb)(char)); + +#endif diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile index 52cbf4f06aab..2e08dacb7b6f 100644 --- a/arch/arm64/kvm/hyp/nvhe/Makefile +++ b/arch/arm64/kvm/hyp/nvhe/Makefile @@ -5,7 +5,8 @@ lib-objs := $(addprefix ../../../lib/, $(lib-objs)) hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o \ hyp-main.o hyp-smp.o psci-relay.o early_alloc.o page_alloc.o \ - cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o ffa.o iommu.o + cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o ffa.o iommu.o \ + serial.o hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \ ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o hyp-obj-$(CONFIG_DEBUG_LIST) += list_debug.o diff --git a/arch/arm64/kvm/hyp/nvhe/modules.c b/arch/arm64/kvm/hyp/nvhe/modules.c index 43c670d4f7cf..b845fe559307 100644 --- a/arch/arm64/kvm/hyp/nvhe/modules.c +++ b/arch/arm64/kvm/hyp/nvhe/modules.c @@ -7,9 +7,11 @@ #include #include +#include const struct pkvm_module_ops module_ops = { .create_private_mapping = __pkvm_create_private_mapping, + .register_serial_driver = __pkvm_register_serial_driver, }; int __pkvm_init_module(void *module_init) diff --git a/arch/arm64/kvm/hyp/nvhe/serial.c b/arch/arm64/kvm/hyp/nvhe/serial.c new file mode 100644 index 000000000000..0b2cf3b6d6a5 --- /dev/null +++ b/arch/arm64/kvm/hyp/nvhe/serial.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 - Google LLC + */ + +#include +#include + +static void (*__hyp_putc)(char c); + +static inline void __hyp_putx4(unsigned int x) +{ + x &= 0xf; + if (x <= 9) + x += '0'; + else + x += ('a' - 0xa); + + __hyp_putc(x); +} + +static inline void __hyp_putx4n(unsigned long x, int n) +{ + int i = n >> 2; + + __hyp_putc('0'); + __hyp_putc('x'); + + while (i--) + __hyp_putx4(x >> (4 * i)); + + __hyp_putc('\n'); + __hyp_putc('\r'); +} + +static inline bool hyp_serial_enabled(void) +{ + return !!READ_ONCE(__hyp_putc); +} + +void hyp_puts(const char *s) +{ + if (!hyp_serial_enabled()) + return; + + while (*s) + __hyp_putc(*s++); + + __hyp_putc('\n'); + __hyp_putc('\r'); +} + +void hyp_putx64(u64 x) +{ + if (hyp_serial_enabled()) + __hyp_putx4n(x, 64); +} + +void hyp_putc(char c) +{ + if (hyp_serial_enabled()) + __hyp_putc(c); +} + +int __pkvm_register_serial_driver(void (*cb)(char)) +{ + return cmpxchg(&__hyp_putc, NULL, cb) ? -EBUSY : 0; +} diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c index 66392411ecaa..5e379f03fcca 100644 --- a/arch/arm64/kvm/hyp/nvhe/setup.c +++ b/arch/arm64/kvm/hyp/nvhe/setup.c @@ -18,6 +18,7 @@ #include #include #include +#include #include unsigned long hyp_nr_cpus;