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;