[PATCH 1/3] hv: add Timed GPIO process handler


chenli.wei
 

From: Chenli Wei <chenli.wei@...>

We need assign TGPIO to some VM, but the TGPIO register in a common page
which we can't assign to user VM directly.

So, this patch add a handler to process the register of TGPIO.

Tracked-On: #6690
Signed-off-by: Chenli Wei <chenli.wei@...>
---
hypervisor/Makefile | 1 +
hypervisor/arch/x86/guest/vm.c | 4 +
hypervisor/dm/vtgpio.c | 84 +++++++++++++++++++++
hypervisor/include/arch/x86/asm/vm_config.h | 2 +
hypervisor/include/dm/vtgpio.h | 12 +++
5 files changed, 103 insertions(+)
create mode 100644 hypervisor/dm/vtgpio.c
create mode 100644 hypervisor/include/dm/vtgpio.h

diff --git a/hypervisor/Makefile b/hypervisor/Makefile
index b72849720..212a70a97 100644
--- a/hypervisor/Makefile
+++ b/hypervisor/Makefile
@@ -327,6 +327,7 @@ VP_DM_C_SRCS += dm/vpci/vsriov.c
VP_DM_C_SRCS += dm/vpci/vmcs9900.c
VP_DM_C_SRCS += dm/mmio_dev.c
VP_DM_C_SRCS += dm/vgpio.c
+VP_DM_C_SRCS += dm/vtgpio.c
VP_DM_C_SRCS += arch/x86/guest/vlapic.c
VP_DM_C_SRCS += arch/x86/guest/pm.c
VP_DM_C_SRCS += arch/x86/guest/assign.c
diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c
index ed66a94f4..6725d9812 100644
--- a/hypervisor/arch/x86/guest/vm.c
+++ b/hypervisor/arch/x86/guest/vm.c
@@ -36,6 +36,7 @@
#include <asm/trampoline.h>
#include <asm/guest/assign.h>
#include <vgpio.h>
+#include <vtgpio.h>
#include <asm/rtcm.h>
#include <asm/irq.h>
#include <uart16550.h>
@@ -378,6 +379,9 @@ static void prepare_prelaunched_vm_memmap(struct acrn_vm *vm, const struct acrn_

(void)assign_mmio_dev(vm, &vm_config->mmiodevs[i]);

+ if (vm_config->pt_tgpio)
+ register_vtgpio_handler(vm);
+
#ifdef P2SB_VGPIO_DM_ENABLED
if ((vm_config->pt_p2sb_bar) && (vm_config->mmiodevs[i].res[0].host_pa == P2SB_BAR_ADDR)) {
register_vgpio_handler(vm, &vm_config->mmiodevs[i].res[0]);
diff --git a/hypervisor/dm/vtgpio.c b/hypervisor/dm/vtgpio.c
new file mode 100644
index 000000000..2b71467fe
--- /dev/null
+++ b/hypervisor/dm/vtgpio.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020-2022 Intel Corporation.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+/*
+* Emulate Timed GPIO registers.
+*
+*/
+
+#include <types.h>
+#include <errno.h>
+#include <asm/guest/vm.h>
+#include <asm/guest/ept.h>
+#include <asm/guest/assign.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <logmsg.h>
+
+/* TODO: Get TIMED_GPIO_BASE from board info */
+#define TIMED_GPIO_BASE 0xFE000000
+
+/* Timed GPIO0 */
+#define TIMED_GPIO_0_OFFSET_BEGIN 0x1210
+#define TIMED_GPIO_0_OFFSET_END 0x1247
+
+/* Timed GPIO1 */
+#define TIMED_GPIO_1_OFFSET_BEGIN 0x1310
+#define TIMED_GPIO_1_OFFSET_END 0x1347
+
+static int32_t vgpio_mmio_handler(struct io_request *io_req, void *data)
+{
+ struct acrn_mmio_request *mmio = &io_req->reqs.mmio_request;
+
+ /* TODO Get TGPIO info from acrn config */
+ struct acrn_vm *vm = (struct acrn_vm *) data;
+ struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
+
+ int32_t ret = 0;
+
+ uint64_t hpa = mmio->address;
+ void *hva = hpa2hva(hpa);
+
+ uint32_t value;
+
+ pr_dbg("Hypervisor Set Timed GPIO for vm %s: ", vm_config->name);
+ /* all gpio registers have 4 bytes size */
+ if (mmio->size == 4U) {
+ if (mmio->direction == ACRN_IOREQ_DIR_READ) {
+ value = mmio_read32((const void *)hva);
+ mmio->value = (uint64_t)value;
+ } else {
+ value = (uint32_t)mmio->value;
+ mmio_write32(value, (void *)hva);
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/**
+ * @pre vm != NULL
+ */
+void register_vtgpio_handler(struct acrn_vm *vm)
+{
+ uint64_t gpa_start, gpa_end, gpio_pcr_sz;
+ uint64_t base_hpa;
+
+ gpa_start = TIMED_GPIO_BASE + TIMED_GPIO_0_OFFSET_BEGIN;
+ base_hpa = TIMED_GPIO_BASE + TIMED_GPIO_0_OFFSET_BEGIN;
+
+ /* include the blank between TGPIO0 and TGPIO1 */
+ gpio_pcr_sz = TIMED_GPIO_1_OFFSET_END - TIMED_GPIO_BASE;
+ gpa_end = TIMED_GPIO_BASE + TIMED_GPIO_1_OFFSET_END;
+
+ /* emulate MMIO access to the Timed GPIO private configuration space registers */
+ set_paging_supervisor((uint64_t)hpa2hva(base_hpa), gpio_pcr_sz);
+ register_mmio_emulation_handler(vm, vgpio_mmio_handler, gpa_start, gpa_end, (void *)vm, false);
+ ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, gpa_start, gpio_pcr_sz);
+}
diff --git a/hypervisor/include/arch/x86/asm/vm_config.h b/hypervisor/include/arch/x86/asm/vm_config.h
index ef80701d6..7dc7b96c6 100644
--- a/hypervisor/include/arch/x86/asm/vm_config.h
+++ b/hypervisor/include/arch/x86/asm/vm_config.h
@@ -207,6 +207,8 @@ struct acrn_vm_config {

uint16_t pt_intx_num; /* number of pt_intx_config entries pointed by pt_intx */
struct pt_intx_config *pt_intx; /* stores the base address of struct pt_intx_config array */
+
+ bool pt_tgpio; /* whether passthrough tgpio to post-launched VM or not */
} __aligned(8);

struct acrn_vm_config *get_vm_config(uint16_t vm_id);
diff --git a/hypervisor/include/dm/vtgpio.h b/hypervisor/include/dm/vtgpio.h
new file mode 100644
index 000000000..fbb699f9f
--- /dev/null
+++ b/hypervisor/include/dm/vtgpio.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2020-2022 Intel Corporation.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VTGPIO_H
+#define VTGPIO_H
+
+void register_vtgpio_handler(struct acrn_vm *vm);
+
+#endif /* VTGPIO_H */
--
2.25.1


Junjie Mao
 

-----Original Message-----
From: Chenli Wei <chenli.wei@...>
Sent: Friday, October 14, 2022 10:25 PM
To: Wang, Yu1 <yu1.wang@...>; Mao, Junjie <junjie.mao@...>; acrn-
dev@...
Cc: Wei, Chenli <chenli.wei@...>
Subject: [PATCH 1/3] hv: add Timed GPIO process handler

From: Chenli Wei <chenli.wei@...>

We need assign TGPIO to some VM, but the TGPIO register in a common page
which we can't assign to user VM directly.

So, this patch add a handler to process the register of TGPIO.

Tracked-On: #6690
Signed-off-by: Chenli Wei <chenli.wei@...>
Please mark the POC patches with "[RFC]" to better reflect the current stage of the series. Also for POC patches you can list the TODOs in the commit messages to let others know what the known gaps are.

---
hypervisor/Makefile | 1 +
hypervisor/arch/x86/guest/vm.c | 4 +
hypervisor/dm/vtgpio.c | 84 +++++++++++++++++++++
hypervisor/include/arch/x86/asm/vm_config.h | 2 +
hypervisor/include/dm/vtgpio.h | 12 +++
5 files changed, 103 insertions(+)
create mode 100644 hypervisor/dm/vtgpio.c
create mode 100644 hypervisor/include/dm/vtgpio.h

diff --git a/hypervisor/Makefile b/hypervisor/Makefile
index b72849720..212a70a97 100644
--- a/hypervisor/Makefile
+++ b/hypervisor/Makefile
@@ -327,6 +327,7 @@ VP_DM_C_SRCS += dm/vpci/vsriov.c
VP_DM_C_SRCS += dm/vpci/vmcs9900.c
VP_DM_C_SRCS += dm/mmio_dev.c
VP_DM_C_SRCS += dm/vgpio.c
+VP_DM_C_SRCS += dm/vtgpio.c
VP_DM_C_SRCS += arch/x86/guest/vlapic.c
VP_DM_C_SRCS += arch/x86/guest/pm.c
VP_DM_C_SRCS += arch/x86/guest/assign.c
diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c
index ed66a94f4..6725d9812 100644
--- a/hypervisor/arch/x86/guest/vm.c
+++ b/hypervisor/arch/x86/guest/vm.c
@@ -36,6 +36,7 @@
#include <asm/trampoline.h>
#include <asm/guest/assign.h>
#include <vgpio.h>
+#include <vtgpio.h>
#include <asm/rtcm.h>
#include <asm/irq.h>
#include <uart16550.h>
@@ -378,6 +379,9 @@ static void prepare_prelaunched_vm_memmap(struct acrn_vm *vm, const
struct acrn_

(void)assign_mmio_dev(vm, &vm_config->mmiodevs[i]);

+ if (vm_config->pt_tgpio)
+ register_vtgpio_handler(vm);
+
#ifdef P2SB_VGPIO_DM_ENABLED
if ((vm_config->pt_p2sb_bar) && (vm_config->mmiodevs[i].res[0].host_pa ==
P2SB_BAR_ADDR)) {
register_vgpio_handler(vm, &vm_config->mmiodevs[i].res[0]);
diff --git a/hypervisor/dm/vtgpio.c b/hypervisor/dm/vtgpio.c
new file mode 100644
index 000000000..2b71467fe
--- /dev/null
+++ b/hypervisor/dm/vtgpio.c
While you can grant access to tGPIO by adding yet another driver, a better approach would be to update assign_mmio_dev() so that it registers I/O handler for sub-page regions while updating EPT if a page-aligned range is given. With that the existing ACPI device granting mechanism can be leveraged.

@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020-2022 Intel Corporation.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+/*
+* Emulate Timed GPIO registers.
+*
+*/
+
+#include <types.h>
+#include <errno.h>
+#include <asm/guest/vm.h>
+#include <asm/guest/ept.h>
+#include <asm/guest/assign.h>
+#include <asm/io.h>
+#include <asm/mmu.h>
+#include <logmsg.h>
+
+/* TODO: Get TIMED_GPIO_BASE from board info */
+#define TIMED_GPIO_BASE 0xFE000000
+
+/* Timed GPIO0 */
+#define TIMED_GPIO_0_OFFSET_BEGIN 0x1210
+#define TIMED_GPIO_0_OFFSET_END 0x1247
+
+/* Timed GPIO1 */
+#define TIMED_GPIO_1_OFFSET_BEGIN 0x1310
+#define TIMED_GPIO_1_OFFSET_END 0x1347
Instead of relying on the config tools, you may expect those parameters coming from hypercalls instead.

---
Best Regards
Junjie Mao

+
+static int32_t vgpio_mmio_handler(struct io_request *io_req, void *data)
+{
+ struct acrn_mmio_request *mmio = &io_req->reqs.mmio_request;
+
+ /* TODO Get TGPIO info from acrn config */
+ struct acrn_vm *vm = (struct acrn_vm *) data;
+ struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
+
+ int32_t ret = 0;
+
+ uint64_t hpa = mmio->address;
+ void *hva = hpa2hva(hpa);
+
+ uint32_t value;
+
+ pr_dbg("Hypervisor Set Timed GPIO for vm %s: ", vm_config->name);
+ /* all gpio registers have 4 bytes size */
+ if (mmio->size == 4U) {
+ if (mmio->direction == ACRN_IOREQ_DIR_READ) {
+ value = mmio_read32((const void *)hva);
+ mmio->value = (uint64_t)value;
+ } else {
+ value = (uint32_t)mmio->value;
+ mmio_write32(value, (void *)hva);
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/**
+ * @pre vm != NULL
+ */
+void register_vtgpio_handler(struct acrn_vm *vm)
+{
+ uint64_t gpa_start, gpa_end, gpio_pcr_sz;
+ uint64_t base_hpa;
+
+ gpa_start = TIMED_GPIO_BASE + TIMED_GPIO_0_OFFSET_BEGIN;
+ base_hpa = TIMED_GPIO_BASE + TIMED_GPIO_0_OFFSET_BEGIN;
+
+ /* include the blank between TGPIO0 and TGPIO1 */
+ gpio_pcr_sz = TIMED_GPIO_1_OFFSET_END - TIMED_GPIO_BASE;
+ gpa_end = TIMED_GPIO_BASE + TIMED_GPIO_1_OFFSET_END;
+
+ /* emulate MMIO access to the Timed GPIO private configuration space registers */
+ set_paging_supervisor((uint64_t)hpa2hva(base_hpa), gpio_pcr_sz);
+ register_mmio_emulation_handler(vm, vgpio_mmio_handler, gpa_start, gpa_end, (void
*)vm, false);
+ ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, gpa_start, gpio_pcr_sz);
+}
diff --git a/hypervisor/include/arch/x86/asm/vm_config.h
b/hypervisor/include/arch/x86/asm/vm_config.h
index ef80701d6..7dc7b96c6 100644
--- a/hypervisor/include/arch/x86/asm/vm_config.h
+++ b/hypervisor/include/arch/x86/asm/vm_config.h
@@ -207,6 +207,8 @@ struct acrn_vm_config {

uint16_t pt_intx_num; /* number of pt_intx_config entries pointed by pt_intx */
struct pt_intx_config *pt_intx; /* stores the base address of struct pt_intx_config
array */
+
+ bool pt_tgpio; /* whether passthrough tgpio to post-launched VM or not */
} __aligned(8);

struct acrn_vm_config *get_vm_config(uint16_t vm_id);
diff --git a/hypervisor/include/dm/vtgpio.h b/hypervisor/include/dm/vtgpio.h
new file mode 100644
index 000000000..fbb699f9f
--- /dev/null
+++ b/hypervisor/include/dm/vtgpio.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2020-2022 Intel Corporation.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VTGPIO_H
+#define VTGPIO_H
+
+void register_vtgpio_handler(struct acrn_vm *vm);
+
+#endif /* VTGPIO_H */
--
2.25.1