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 <vdonnefort@google.com> Signed-off-by: Quentin Perret <qperret@google.com> Change-Id: Id56bd3f39e91da490e97e8683a8cc7454497035b
This commit is contained in:
committed by
Keir Fraser
parent
8903638740
commit
1a8bda12e0
@@ -1603,3 +1603,5 @@ endmenu
|
||||
|
||||
config SERIAL_MCTRL_GPIO
|
||||
tristate
|
||||
|
||||
source "drivers/tty/serial/pkvm-pl011/Kconfig"
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
hyp-reloc.S
|
||||
hyp.lds
|
||||
@@ -0,0 +1,2 @@
|
||||
hyp-obj-y := pl011-hyp.o
|
||||
include $(srctree)/arch/arm64/kvm/hyp/nvhe/Makefile.module
|
||||
@@ -0,0 +1,54 @@
|
||||
#include <asm/alternative-macros.h>
|
||||
#include <asm/barrier.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/kvm_pkvm_module.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
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 <<CONFIG_SERIAL_PKVM_PL011_FULL));
|
||||
dmb(sy);
|
||||
|
||||
__hyp_writew(c, base + CONFIG_SERIAL_PKVM_PL011_UARTTX);
|
||||
|
||||
do {
|
||||
val = __hyp_readw(base + CONFIG_SERIAL_PKVM_PL011_UARTFR);
|
||||
} while (val & (1U << CONFIG_SERIAL_PKVM_PL011_BUSY));
|
||||
dmb(sy);
|
||||
}
|
||||
|
||||
int pl011_hyp_init(const struct pkvm_module_ops *ops)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ops->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;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include <asm/kvm_pkvm_module.h>
|
||||
|
||||
#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");
|
||||
Reference in New Issue
Block a user