From 1a8bda12e0e953d8b55f264a3ca0e33a508965ab Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Fri, 16 Sep 2022 11:47:07 +0100 Subject: [PATCH] ANDROID: drivers: misc: Add an example pl011 driver for pKVM This is an example pl011 driver that has been tuned for the Google Pixel devices only! Its main purpose is to demonstrate how to use the newly introduce pKVM module loading feature. Bug: 357781595 Signed-off-by: Vincent Donnefort Signed-off-by: Quentin Perret Change-Id: Id56bd3f39e91da490e97e8683a8cc7454497035b --- drivers/tty/serial/Kconfig | 2 + drivers/tty/serial/Makefile | 2 + drivers/tty/serial/pkvm-pl011/Kconfig | 31 +++++++++++ drivers/tty/serial/pkvm-pl011/Makefile | 8 +++ drivers/tty/serial/pkvm-pl011/hyp/.gitignore | 2 + drivers/tty/serial/pkvm-pl011/hyp/Makefile | 2 + drivers/tty/serial/pkvm-pl011/hyp/pl011-hyp.c | 54 +++++++++++++++++++ drivers/tty/serial/pkvm-pl011/pl011-host.c | 26 +++++++++ 8 files changed, 127 insertions(+) create mode 100644 drivers/tty/serial/pkvm-pl011/Kconfig create mode 100644 drivers/tty/serial/pkvm-pl011/Makefile create mode 100644 drivers/tty/serial/pkvm-pl011/hyp/.gitignore create mode 100644 drivers/tty/serial/pkvm-pl011/hyp/Makefile create mode 100644 drivers/tty/serial/pkvm-pl011/hyp/pl011-hyp.c create mode 100644 drivers/tty/serial/pkvm-pl011/pl011-host.c diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 72f2318dec86..8007c0a84c1a 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1603,3 +1603,5 @@ endmenu config SERIAL_MCTRL_GPIO tristate + +source "drivers/tty/serial/pkvm-pl011/Kconfig" diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 6ff74f0a9530..e0ecdc2e7e14 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -99,3 +99,5 @@ obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_NUVOTON_MA35D1) += ma35d1_serial.o + +obj-$(CONFIG_SERIAL_PKVM_PL011) += pkvm-pl011/ diff --git a/drivers/tty/serial/pkvm-pl011/Kconfig b/drivers/tty/serial/pkvm-pl011/Kconfig new file mode 100644 index 000000000000..772825a57cda --- /dev/null +++ b/drivers/tty/serial/pkvm-pl011/Kconfig @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0 + +config SERIAL_PKVM_PL011 + tristate "Protected KVM PL011 UART" + depends on ARM64 + depends on KVM + +config SERIAL_PKVM_PL011_BASE_PHYS + hex + depends on SERIAL_PKVM_PL011 + default 0x09000000 + +config SERIAL_PKVM_PL011_UARTFR + hex + depends on SERIAL_PKVM_PL011 + default 0x18 + +config SERIAL_PKVM_PL011_UARTTX + hex + depends on SERIAL_PKVM_PL011 + default 0x0 + +config SERIAL_PKVM_PL011_BUSY + hex + depends on SERIAL_PKVM_PL011 + default 0x2 + +config SERIAL_PKVM_PL011_FULL + hex + depends on SERIAL_PKVM_PL011 + default 0x6 diff --git a/drivers/tty/serial/pkvm-pl011/Makefile b/drivers/tty/serial/pkvm-pl011/Makefile new file mode 100644 index 000000000000..be22f1348539 --- /dev/null +++ b/drivers/tty/serial/pkvm-pl011/Makefile @@ -0,0 +1,8 @@ +obj-m += pkvm_pl011.o + +$(obj)/hyp/kvm_nvhe.o: FORCE + $(Q)$(MAKE) $(build)=$(obj)/hyp $(obj)/hyp/kvm_nvhe.o + +clean-files := hyp/hyp.lds hyp/hyp-reloc.S + +pkvm_pl011-y := pl011-host.o hyp/kvm_nvhe.o diff --git a/drivers/tty/serial/pkvm-pl011/hyp/.gitignore b/drivers/tty/serial/pkvm-pl011/hyp/.gitignore new file mode 100644 index 000000000000..185e3ad69ca2 --- /dev/null +++ b/drivers/tty/serial/pkvm-pl011/hyp/.gitignore @@ -0,0 +1,2 @@ +hyp-reloc.S +hyp.lds diff --git a/drivers/tty/serial/pkvm-pl011/hyp/Makefile b/drivers/tty/serial/pkvm-pl011/hyp/Makefile new file mode 100644 index 000000000000..82765177d962 --- /dev/null +++ b/drivers/tty/serial/pkvm-pl011/hyp/Makefile @@ -0,0 +1,2 @@ +hyp-obj-y := pl011-hyp.o +include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module diff --git a/drivers/tty/serial/pkvm-pl011/hyp/pl011-hyp.c b/drivers/tty/serial/pkvm-pl011/hyp/pl011-hyp.c new file mode 100644 index 000000000000..30090c4b07f4 --- /dev/null +++ b/drivers/tty/serial/pkvm-pl011/hyp/pl011-hyp.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include + +static unsigned long uart_addr; + +static inline unsigned int __hyp_readw(void *ioaddr) +{ + unsigned int val; + asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (ioaddr)); + return val; +} +static inline void __hyp_writew(unsigned int val, void *ioaddr) +{ + asm volatile("str %w0, [%1]" : : "r" (val), "r" (ioaddr)); +} + +static void pl011_hyp_putc(char c) +{ + void *base = (void *)uart_addr; + unsigned int val; + + do { + val = __hyp_readw(base + CONFIG_SERIAL_PKVM_PL011_UARTFR); + } while (val & (1U <create_private_mapping(CONFIG_SERIAL_PKVM_PL011_BASE_PHYS, PAGE_SIZE, + PAGE_HYP_DEVICE, &uart_addr); + if (ret) + return ret; + + ret = ops->register_serial_driver(pl011_hyp_putc); + if (ret) + return ret; + + ops->puts("pKVM pl011 UART driver loaded"); + + return 0; +} diff --git a/drivers/tty/serial/pkvm-pl011/pl011-host.c b/drivers/tty/serial/pkvm-pl011/pl011-host.c new file mode 100644 index 000000000000..797a6abbb1f9 --- /dev/null +++ b/drivers/tty/serial/pkvm-pl011/pl011-host.c @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +#ifndef MODULE +BUILD_BUG("pKVM pl011 UART must be compiled as a module"); +#endif + +int __kvm_nvhe_pl011_hyp_init(const struct pkvm_module_ops *ops); + +static int __init pl011_nvhe_init(void) +{ + unsigned long token; + int ret; + + ret = pkvm_load_el2_module(__kvm_nvhe_pl011_hyp_init, &token); + if (ret) + return ret; + + return 0; +} +module_init(pl011_nvhe_init); + +MODULE_LICENSE("GPL");