[PATCH 0/8] RISC-V SBI Nested Acceleration Implementation for Xvisor

26 views
Skip to first unread message

Anup Patel

unread,
Jul 1, 2024, 11:00:58 AM7/1/24
to xvisor...@googlegroups.com, Anup Patel
This series adds RISC-V SBI nested acceleration implementation for
Xvisor RISC-V.

These patches can also be found in riscv_sbi_nested_v1 branch at:
https://github.com/avpatel/xvisor-next.git

Anup Patel (8):
RISC-V: Count the guest page faults redirected to the Guest
RISC-V: Use bitfields in struct arch_pgflags
RISC-V: Increase the SWTLB size used for nested virtualization
RISC-V: Remove redundant timer event from struct riscv_priv_nested
RISC-V: Add defines for the SBI nested acceleration extension
RISC-V: Extend nested virtualization for shared memory based CSR
access
RISC-V: Extend nested virtualization for shared memory based HFENCE
RISC-V: Implement SBI nested acceleration extension

arch/riscv/cpu/generic/cpu_vcpu_helper.c | 37 +-
arch/riscv/cpu/generic/cpu_vcpu_nested.c | 423 ++++++++++++++++--
arch/riscv/cpu/generic/cpu_vcpu_sbi.c | 6 +-
arch/riscv/cpu/generic/cpu_vcpu_sbi_nacl.c | 97 ++++
arch/riscv/cpu/generic/cpu_vcpu_trap.c | 8 +-
arch/riscv/cpu/generic/include/arch_mmu.h | 18 +-
arch/riscv/cpu/generic/include/arch_regs.h | 7 +-
.../cpu/generic/include/cpu_vcpu_nested.h | 26 ++
arch/riscv/cpu/generic/include/riscv_sbi.h | 103 +++++
arch/riscv/cpu/generic/objects.mk | 1 +
10 files changed, 666 insertions(+), 60 deletions(-)
create mode 100644 arch/riscv/cpu/generic/cpu_vcpu_sbi_nacl.c

--
2.34.1

Anup Patel

unread,
Jul 1, 2024, 11:01:01 AM7/1/24
to xvisor...@googlegroups.com, Anup Patel
Some of the guest page faults handled while running nested guest are
redirected to the guest hypervisor. We should count these redirected
guest page faults since they provides useful insight into MMIO traps
handled by the guest hypervisor.

Signed-off-by: Anup Patel <apa...@ventanamicro.com>
---
arch/riscv/cpu/generic/cpu_vcpu_helper.c | 37 ++++++++++++++--------
arch/riscv/cpu/generic/cpu_vcpu_nested.c | 13 ++++++++
arch/riscv/cpu/generic/include/arch_regs.h | 3 ++
3 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/arch/riscv/cpu/generic/cpu_vcpu_helper.c b/arch/riscv/cpu/generic/cpu_vcpu_helper.c
index 2ca54fb3..eecda785 100644
--- a/arch/riscv/cpu/generic/cpu_vcpu_helper.c
+++ b/arch/riscv/cpu/generic/cpu_vcpu_helper.c
@@ -639,7 +639,7 @@ void arch_vcpu_stat_dump(struct vmm_chardev *cdev, struct vmm_vcpu *vcpu)
if (!riscv_stats_priv(vcpu)->trap[i]) {
continue;
}
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n", trap_names[i],
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n", trap_names[i],
riscv_stats_priv(vcpu)->trap[i]);
have_traps = TRUE;
}
@@ -648,43 +648,52 @@ void arch_vcpu_stat_dump(struct vmm_chardev *cdev, struct vmm_vcpu *vcpu)
vmm_cprintf(cdev, "\n");
}

- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested Enter",
riscv_stats_priv(vcpu)->nested_enter);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested Exit",
riscv_stats_priv(vcpu)->nested_exit);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested Virtual Interrupt",
riscv_stats_priv(vcpu)->nested_vsirq);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested S-mode CSR Access",
riscv_stats_priv(vcpu)->nested_smode_csr_rmw);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested HS-mode CSR Access",
riscv_stats_priv(vcpu)->nested_hext_csr_rmw);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested Load Guest Page Fault",
riscv_stats_priv(vcpu)->nested_load_guest_page_fault);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested Store Guest Page Fault",
riscv_stats_priv(vcpu)->nested_store_guest_page_fault);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested Fetch Guest Page Fault",
riscv_stats_priv(vcpu)->nested_fetch_guest_page_fault);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
+ "Nested Redirect Load Guest Page Fault",
+ riscv_stats_priv(vcpu)->nested_redir_load_guest_page_fault);
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
+ "Nested Redirect Store Guest Page Fault",
+ riscv_stats_priv(vcpu)->nested_redir_store_guest_page_fault);
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
+ "Nested Redirect Fetch Guest Page Fault",
+ riscv_stats_priv(vcpu)->nested_redir_fetch_guest_page_fault);
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested HFENCE.VVMA Instruction",
riscv_stats_priv(vcpu)->nested_hfence_vvma);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested HFENCE.GVMA Instruction",
riscv_stats_priv(vcpu)->nested_hfence_gvma);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested HLV Instruction",
riscv_stats_priv(vcpu)->nested_hlv);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested HSV Instruction",
riscv_stats_priv(vcpu)->nested_hsv);
- vmm_cprintf(cdev, "%-32s: 0x%"PRIx64"\n",
+ vmm_cprintf(cdev, "%-40s: 0x%"PRIx64"\n",
"Nested SBI Ecall",
riscv_stats_priv(vcpu)->nested_sbi);
}
diff --git a/arch/riscv/cpu/generic/cpu_vcpu_nested.c b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
index d5c68b8f..92927f34 100644
--- a/arch/riscv/cpu/generic/cpu_vcpu_nested.c
+++ b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
@@ -1442,6 +1442,19 @@ int cpu_vcpu_nested_page_fault(struct vmm_vcpu *vcpu,
csr_read(CSR_VSSTATUS), FALSE);
rc = nested_xlate_gstage(&xc, guest_gpa, guest_access);
if (rc == VMM_EFAULT) {
+ switch (xc.scause) {
+ case CAUSE_LOAD_GUEST_PAGE_FAULT:
+ riscv_stats_priv(vcpu)->nested_redir_load_guest_page_fault++;
+ break;
+ case CAUSE_STORE_GUEST_PAGE_FAULT:
+ riscv_stats_priv(vcpu)->nested_redir_store_guest_page_fault++;
+ break;
+ case CAUSE_FETCH_GUEST_PAGE_FAULT:
+ riscv_stats_priv(vcpu)->nested_redir_fetch_guest_page_fault++;
+ break;
+ default:
+ break;
+ }
out_trap->sepc = trap->sepc;
out_trap->scause = xc.scause;
out_trap->stval = trap->stval;
diff --git a/arch/riscv/cpu/generic/include/arch_regs.h b/arch/riscv/cpu/generic/include/arch_regs.h
index fa1973f7..946b5989 100644
--- a/arch/riscv/cpu/generic/include/arch_regs.h
+++ b/arch/riscv/cpu/generic/include/arch_regs.h
@@ -199,6 +199,9 @@ struct riscv_priv_stats {
u64 nested_load_guest_page_fault;
u64 nested_store_guest_page_fault;
u64 nested_fetch_guest_page_fault;
+ u64 nested_redir_load_guest_page_fault;
+ u64 nested_redir_store_guest_page_fault;
+ u64 nested_redir_fetch_guest_page_fault;
u64 nested_hfence_vvma;
u64 nested_hfence_gvma;
u64 nested_hlv;
--
2.34.1

Anup Patel

unread,
Jul 1, 2024, 11:01:01 AM7/1/24
to xvisor...@googlegroups.com, Anup Patel
The struct arch_pgflags is embedded in struct mmu_page and the later is
widely used everywhere (particularly in shadow TLB implementation for
nested virtualization). We should use bitfields in struct arch_pgflags
to reduce memory consumed by struct mmu_page.

Signed-off-by: Anup Patel <apa...@ventanamicro.com>
---
arch/riscv/cpu/generic/include/arch_mmu.h | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/arch/riscv/cpu/generic/include/arch_mmu.h b/arch/riscv/cpu/generic/include/arch_mmu.h
index d7adfd66..6ae05b60 100644
--- a/arch/riscv/cpu/generic/include/arch_mmu.h
+++ b/arch/riscv/cpu/generic/include/arch_mmu.h
@@ -121,15 +121,15 @@ typedef u32 arch_pte_t;
#endif

struct arch_pgflags {
- u8 rsw;
- u8 dirty;
- u8 accessed;
- u8 global;
- u8 user;
- u8 execute;
- u8 write;
- u8 read;
- u8 valid;
+ u16 rsw:2;
+ u16 dirty:1;
+ u16 accessed:1;
+ u16 global:1;
+ u16 user:1;
+ u16 execute:1;
+ u16 write:1;
+ u16 read:1;
+ u16 valid:1;
};
typedef struct arch_pgflags arch_pgflags_t;

--
2.34.1

Anup Patel

unread,
Jul 1, 2024, 11:01:05 AM7/1/24
to xvisor...@googlegroups.com, Anup Patel
Currently, we only have 256 (128 + 128) enteries in the per-VCPU SWTLB
used for nested virtualization which means at any point in time the
shadow G-stage for nested guest will only have upto 1MB address mapping
for 4KB page size.

This is too restrictive and slow when guest hypervisor is using 4KB
mappings in the G-stage it creates for nested guest so let us increase
the per-VCPU SWTLB enteries to 2048 (1024 + 1024) which allows upto 8MB
address mapping for 4KB page size.

Signed-off-by: Anup Patel <apa...@ventanamicro.com>
---
arch/riscv/cpu/generic/cpu_vcpu_nested.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/cpu/generic/cpu_vcpu_nested.c b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
index 92927f34..b3aa23b8 100644
--- a/arch/riscv/cpu/generic/cpu_vcpu_nested.c
+++ b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
@@ -46,8 +46,8 @@
* 2) Change in guest hgatp.VMID
*/

-#define NESTED_SWTLB_ITLB_MAX_ENTRY 128
-#define NESTED_SWTLB_DTLB_MAX_ENTRY 128
+#define NESTED_SWTLB_ITLB_MAX_ENTRY 1024
+#define NESTED_SWTLB_DTLB_MAX_ENTRY 1024
#define NESTED_SWTLB_MAX_ENTRY (NESTED_SWTLB_ITLB_MAX_ENTRY + \
NESTED_SWTLB_DTLB_MAX_ENTRY)

--
2.34.1

Anup Patel

unread,
Jul 1, 2024, 11:01:07 AM7/1/24
to xvisor...@googlegroups.com, Anup Patel
The timer event in struct riscv_priv_nested was intended to be used for
nested guest but we have separate timer event in cpu_vcpu_timer for this
purpose so let us remove timer event from struct riscv_priv_nested.

Signed-off-by: Anup Patel <apa...@ventanamicro.com>
---
arch/riscv/cpu/generic/cpu_vcpu_nested.c | 23 +---------------------
arch/riscv/cpu/generic/include/arch_regs.h | 2 --
2 files changed, 1 insertion(+), 24 deletions(-)

diff --git a/arch/riscv/cpu/generic/cpu_vcpu_nested.c b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
index b3aa23b8..658560fa 100644
--- a/arch/riscv/cpu/generic/cpu_vcpu_nested.c
+++ b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
@@ -796,25 +796,12 @@ static int nested_xlate_vsstage(struct nested_xlate_context *xc,
return VMM_OK;
}

-static void nested_timer_event_expired(struct vmm_timer_event *ev)
-{
- /* Do nothing */
-}
-
int cpu_vcpu_nested_init(struct vmm_vcpu *vcpu)
{
int rc;
- struct vmm_timer_event *event;
u32 pgtbl_attr = 0, pgtbl_hw_tag = 0;
struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);

- event = vmm_zalloc(sizeof(struct vmm_timer_event));
- if (!event) {
- return VMM_ENOMEM;
- }
- INIT_TIMER_EVENT(event, nested_timer_event_expired, vcpu);
- npriv->timer_event = event;
-
if (riscv_stage2_vmid_available()) {
pgtbl_hw_tag = riscv_stage2_vmid_nested + vcpu->guest->id;
pgtbl_attr |= MMU_ATTR_HW_TAG_VALID;
@@ -822,14 +809,12 @@ int cpu_vcpu_nested_init(struct vmm_vcpu *vcpu)
npriv->pgtbl = mmu_pgtbl_alloc(MMU_STAGE2, -1, pgtbl_attr,
pgtbl_hw_tag);
if (!npriv->pgtbl) {
- vmm_free(npriv->timer_event);
return VMM_ENOMEM;
}

rc = nested_swtlb_init(vcpu);
if (rc) {
mmu_pgtbl_free(npriv->pgtbl);
- vmm_free(npriv->timer_event);
return rc;
}

@@ -840,7 +825,6 @@ void cpu_vcpu_nested_reset(struct vmm_vcpu *vcpu)
{
struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);

- vmm_timer_event_stop(npriv->timer_event);
cpu_vcpu_nested_swtlb_flush(vcpu, 0, 0);
npriv->virt = FALSE;
#ifdef CONFIG_64BIT
@@ -877,7 +861,6 @@ void cpu_vcpu_nested_deinit(struct vmm_vcpu *vcpu)

nested_swtlb_deinit(vcpu);
mmu_pgtbl_free(npriv->pgtbl);
- vmm_free(npriv->timer_event);
}

void cpu_vcpu_nested_dump_regs(struct vmm_chardev *cdev,
@@ -1788,15 +1771,11 @@ void cpu_vcpu_nested_take_vsirq(struct vmm_vcpu *vcpu,

/*
* If we going to virtual-VS mode and interrupts are disabled
- * then start nested timer event.
+ * then do nothing.
*/
if (next_spp && !(csr_read(CSR_VSSTATUS) & SSTATUS_SIE)) {
- if (!vmm_timer_event_pending(npriv->timer_event)) {
- vmm_timer_event_start(npriv->timer_event, 10000000);
- }
return;
}
- vmm_timer_event_stop(npriv->timer_event);

riscv_stats_priv(vcpu)->nested_vsirq++;

diff --git a/arch/riscv/cpu/generic/include/arch_regs.h b/arch/riscv/cpu/generic/include/arch_regs.h
index 946b5989..b09d0aa2 100644
--- a/arch/riscv/cpu/generic/include/arch_regs.h
+++ b/arch/riscv/cpu/generic/include/arch_regs.h
@@ -157,8 +157,6 @@ union riscv_priv_fp {
struct riscv_priv_nested {
/* Nested virt state */
bool virt;
- /* Nested interrupts timer event */
- void *timer_event;
/* Nested software TLB */
void *swtlb;
/* Nested shadow page table */
--
2.34.1

Anup Patel

unread,
Jul 1, 2024, 11:01:08 AM7/1/24
to xvisor...@googlegroups.com, Anup Patel
We add defines for the new SBI nested acceleration extension in the
SBI interface header.

Signed-off-by: Anup Patel <apa...@ventanamicro.com>
---
arch/riscv/cpu/generic/cpu_vcpu_sbi.c | 4 +-
arch/riscv/cpu/generic/include/riscv_sbi.h | 103 +++++++++++++++++++++
2 files changed, 106 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/cpu/generic/cpu_vcpu_sbi.c b/arch/riscv/cpu/generic/cpu_vcpu_sbi.c
index c11cd9fe..b97a560f 100644
--- a/arch/riscv/cpu/generic/cpu_vcpu_sbi.c
+++ b/arch/riscv/cpu/generic/cpu_vcpu_sbi.c
@@ -193,7 +193,6 @@ int cpu_vcpu_sbi_xlate_error(int xvisor_error)

case VMM_ENOTAVAIL:
case VMM_ENOENT:
- case VMM_ENOSYS:
case VMM_ENODEV:
case VMM_EOPNOTSUPP:
case VMM_ENOTSUPP:
@@ -212,6 +211,9 @@ int cpu_vcpu_sbi_xlate_error(int xvisor_error)
case VMM_EEXIST:
return SBI_ERR_ALREADY_AVAILABLE;

+ case VMM_ENOSYS:
+ return SBI_ERR_NO_SHMEM;
+
default:
break;
}
diff --git a/arch/riscv/cpu/generic/include/riscv_sbi.h b/arch/riscv/cpu/generic/include/riscv_sbi.h
index fc621afb..11b5bf50 100644
--- a/arch/riscv/cpu/generic/include/riscv_sbi.h
+++ b/arch/riscv/cpu/generic/include/riscv_sbi.h
@@ -44,6 +44,7 @@
#define SBI_EXT_SRST 0x53525354
#define SBI_EXT_PMU 0x504D55
#define SBI_EXT_DBCN 0x4442434E
+#define SBI_EXT_NACL 0x4E41434C

/* SBI function IDs for BASE extension */
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -244,6 +245,107 @@ enum sbi_pmu_ctr_type {
#define SBI_EXT_DBCN_CONSOLE_READ 0x1
#define SBI_EXT_DBCN_CONSOLE_WRITE_BYTE 0x2

+/* SBI function IDs for NACL extension */
+#define SBI_EXT_NACL_PROBE_FEATURE 0x0
+#define SBI_EXT_NACL_SET_SHMEM 0x1
+#define SBI_EXT_NACL_SYNC_CSR 0x2
+#define SBI_EXT_NACL_SYNC_HFENCE 0x3
+#define SBI_EXT_NACL_SYNC_SRET 0x4
+
+#define SBI_NACL_FEAT_SYNC_CSR 0x0
+#define SBI_NACL_FEAT_SYNC_HFENCE 0x1
+#define SBI_NACL_FEAT_SYNC_SRET 0x2
+#define SBI_NACL_FEAT_AUTOSWAP_CSR 0x3
+
+#define SBI_NACL_SHMEM_ADDR_SHIFT 12
+#define SBI_NACL_SHMEM_SCRATCH_OFFSET 0x0000
+#define SBI_NACL_SHMEM_SCRATCH_SIZE 0x1000
+#define SBI_NACL_SHMEM_SRET_OFFSET 0x0000
+#define SBI_NACL_SHMEM_SRET_SIZE 0x0200
+#define SBI_NACL_SHMEM_AUTOSWAP_OFFSET (SBI_NACL_SHMEM_SRET_OFFSET + \
+ SBI_NACL_SHMEM_SRET_SIZE)
+#define SBI_NACL_SHMEM_AUTOSWAP_SIZE 0x0080
+#define SBI_NACL_SHMEM_UNUSED_OFFSET (SBI_NACL_SHMEM_AUTOSWAP_OFFSET + \
+ SBI_NACL_SHMEM_AUTOSWAP_SIZE)
+#define SBI_NACL_SHMEM_UNUSED_SIZE 0x0580
+#define SBI_NACL_SHMEM_HFENCE_OFFSET (SBI_NACL_SHMEM_UNUSED_OFFSET + \
+ SBI_NACL_SHMEM_UNUSED_SIZE)
+#define SBI_NACL_SHMEM_HFENCE_SIZE 0x0780
+#define SBI_NACL_SHMEM_DBITMAP_OFFSET (SBI_NACL_SHMEM_HFENCE_OFFSET + \
+ SBI_NACL_SHMEM_HFENCE_SIZE)
+#define SBI_NACL_SHMEM_DBITMAP_SIZE 0x0080
+#define SBI_NACL_SHMEM_CSR_OFFSET (SBI_NACL_SHMEM_DBITMAP_OFFSET + \
+ SBI_NACL_SHMEM_DBITMAP_SIZE)
+#define SBI_NACL_SHMEM_CSR_SIZE ((__riscv_xlen / 8) * 1024)
+#define SBI_NACL_SHMEM_SIZE (SBI_NACL_SHMEM_CSR_OFFSET + \
+ SBI_NACL_SHMEM_CSR_SIZE)
+
+#define SBI_NACL_SHMEM_CSR_INDEX(__csr_num) \
+ ((((__csr_num) & 0xc00) >> 2) | ((__csr_num) & 0xff))
+
+#define SBI_NACL_SHMEM_HFENCE_ENTRY_SZ ((__riscv_xlen / 8) * 4)
+#define SBI_NACL_SHMEM_HFENCE_ENTRY_MAX \
+ (SBI_NACL_SHMEM_HFENCE_SIZE / \
+ SBI_NACL_SHMEM_HFENCE_ENTRY_SZ)
+#define SBI_NACL_SHMEM_HFENCE_ENTRY(__num) \
+ (SBI_NACL_SHMEM_HFENCE_OFFSET + \
+ (__num) * SBI_NACL_SHMEM_HFENCE_ENTRY_SZ)
+#define SBI_NACL_SHMEM_HFENCE_ENTRY_CTRL(__num) \
+ SBI_NACL_SHMEM_HFENCE_ENTRY(__num)
+#define SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(__num)\
+ (SBI_NACL_SHMEM_HFENCE_ENTRY(__num) + (__riscv_xlen / 8))
+#define SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(__num)\
+ (SBI_NACL_SHMEM_HFENCE_ENTRY(__num) + \
+ ((__riscv_xlen / 8) * 3))
+
+#if __riscv_xlen == 32
+#define SBI_NACL_SHMEM_HFENCE_CTRL_ASID_BITS 9
+#define SBI_NACL_SHMEM_HFENCE_CTRL_VMID_BITS 7
+#else
+#define SBI_NACL_SHMEM_HFENCE_CTRL_ASID_BITS 16
+#define SBI_NACL_SHMEM_HFENCE_CTRL_VMID_BITS 14
+#endif
+#define SBI_NACL_SHMEM_HFENCE_CTRL_VMID_SHIFT \
+ SBI_NACL_SHMEM_HFENCE_CTRL_ASID_BITS
+#define SBI_NACL_SHMEM_HFENCE_CTRL_ASID_MASK \
+ ((1UL << SBI_NACL_SHMEM_HFENCE_CTRL_ASID_BITS) - 1)
+#define SBI_NACL_SHMEM_HFENCE_CTRL_VMID_MASK \
+ ((1UL << SBI_NACL_SHMEM_HFENCE_CTRL_VMID_BITS) - 1)
+
+#define SBI_NACL_SHMEM_HFENCE_CTRL_ORDER_BITS 7
+#define SBI_NACL_SHMEM_HFENCE_CTRL_ORDER_SHIFT (__riscv_xlen - 16)
+#define SBI_NACL_SHMEM_HFENCE_CTRL_ORDER_MASK \
+ ((1UL << SBI_NACL_SHMEM_HFENCE_CTRL_ORDER_BITS) - 1)
+#define SBI_NACL_SHMEM_HFENCE_ORDER_BASE 12
+
+#define SBI_NACL_SHMEM_HFENCE_CTRL_TYPE_BITS 4
+#define SBI_NACL_SHMEM_HFENCE_CTRL_TYPE_SHIFT (__riscv_xlen - 8)
+#define SBI_NACL_SHMEM_HFENCE_CTRL_TYPE_MASK \
+ ((1UL << SBI_NACL_SHMEM_HFENCE_CTRL_TYPE_BITS) - 1)
+
+#define SBI_NACL_SHMEM_HFENCE_TYPE_GVMA 0x0
+#define SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_ALL 0x1
+#define SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_VMID 0x2
+#define SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_VMID_ALL 0x3
+#define SBI_NACL_SHMEM_HFENCE_TYPE_VVMA 0x4
+#define SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ALL 0x5
+#define SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ASID 0x6
+#define SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ASID_ALL 0x7
+
+#define SBI_NACL_SHMEM_HFENCE_CTRL_PEND_BITS 1
+#define SBI_NACL_SHMEM_HFENCE_CTRL_PEND_SHIFT (__riscv_xlen - 1)
+#define SBI_NACL_SHMEM_HFENCE_CTRL_PEND_MASK \
+ ((1UL << SBI_NACL_SHMEM_HFENCE_CTRL_PEND_BITS) - 1)
+#define SBI_NACL_SHMEM_HFENCE_CTRL_PEND \
+ (SBI_NACL_SHMEM_HFENCE_CTRL_PEND_MASK << \
+ SBI_NACL_SHMEM_HFENCE_CTRL_PEND_SHIFT)
+
+#define SBI_NACL_SHMEM_AUTOSWAP_FLAG_HSTATUS (1 << 0)
+#define SBI_NACL_SHMEM_AUTOSWAP_HSTATUS ((__riscv_xlen / 8) * 1)
+
+#define SBI_NACL_SHMEM_SRET_X(__i) ((__riscv_xlen / 8) * (__i))
+#define SBI_NACL_SHMEM_SRET_X_LAST 31
+
/* SBI base specification related macros */
#define SBI_SPEC_VERSION_MAJOR_SHIFT 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
@@ -267,6 +369,7 @@ enum sbi_pmu_ctr_type {
#define SBI_ERR_ALREADY_AVAILABLE -6
#define SBI_ERR_ALREADY_STARTED -7
#define SBI_ERR_ALREADY_STOPPED -8
+#define SBI_ERR_NO_SHMEM -9

#define SBI_LAST_ERR SBI_ERR_ALREADY_STOPPED

--
2.34.1

Anup Patel

unread,
Jul 1, 2024, 11:01:10 AM7/1/24
to xvisor...@googlegroups.com, Anup Patel
The CSR access traps from Guest Hypervisor to Host Hypervisor add
considerable overhead for nested virtualization. This patch extends
the nested virtualization to allow shared memory based access of
h<xyz> and vs<xyz> CSRs for the Guest Hypervisor.

The SBI nested accleration extension will provide a mechanism to
setup the shared memory from Guest Hypervisor.

Signed-off-by: Anup Patel <apa...@ventanamicro.com>
---
arch/riscv/cpu/generic/cpu_vcpu_nested.c | 262 +++++++++++++++++-
arch/riscv/cpu/generic/cpu_vcpu_trap.c | 8 +-
arch/riscv/cpu/generic/include/arch_regs.h | 2 +
.../cpu/generic/include/cpu_vcpu_nested.h | 22 ++
4 files changed, 284 insertions(+), 10 deletions(-)

diff --git a/arch/riscv/cpu/generic/cpu_vcpu_nested.c b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
index 658560fa..83fc199e 100644
--- a/arch/riscv/cpu/generic/cpu_vcpu_nested.c
+++ b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
@@ -27,6 +27,7 @@
#include <vmm_timer.h>
#include <vmm_guest_aspace.h>
#include <vmm_host_aspace.h>
+#include <vmm_host_io.h>
#include <generic_mmu.h>
#include <libs/list.h>

@@ -37,6 +38,7 @@
#include <cpu_vcpu_timer.h>
#include <cpu_vcpu_trap.h>
#include <riscv_csr.h>
+#include <riscv_sbi.h>

/*
* We share the same host VMID between virtual-HS/U modes and
@@ -827,6 +829,10 @@ void cpu_vcpu_nested_reset(struct vmm_vcpu *vcpu)

cpu_vcpu_nested_swtlb_flush(vcpu, 0, 0);
npriv->virt = FALSE;
+ if (npriv->shmem) {
+ vmm_host_memunmap((virtual_addr_t)npriv->shmem);
+ npriv->shmem = NULL;
+ }
#ifdef CONFIG_64BIT
npriv->hstatus = HSTATUS_VSXL_RV64 << HSTATUS_VSXL_SHIFT;
#else
@@ -1041,9 +1047,13 @@ int cpu_vcpu_nested_smode_csr_rmw(struct vmm_vcpu *vcpu, arch_regs_t *regs,
return VMM_OK;
}

-int cpu_vcpu_nested_hext_csr_rmw(struct vmm_vcpu *vcpu, arch_regs_t *regs,
- unsigned int csr_num, unsigned long *val,
- unsigned long new_val, unsigned long wr_mask)
+static int __cpu_vcpu_nested_hext_csr_rmw(struct vmm_vcpu *vcpu,
+ arch_regs_t *regs,
+ bool priv_check,
+ unsigned int csr_num,
+ unsigned long *val,
+ unsigned long new_val,
+ unsigned long wr_mask)
{
u64 tmp64;
int csr_shift = 0;
@@ -1053,8 +1063,6 @@ int cpu_vcpu_nested_hext_csr_rmw(struct vmm_vcpu *vcpu, arch_regs_t *regs,
unsigned long mode, zero = 0, writeable_mask = 0;
struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);

- riscv_stats_priv(vcpu)->nested_hext_csr_rmw++;
-
/*
* Trap from virtual-VS and virtual-VU modes should be forwarded
* to virtual-HS mode as a virtual instruction trap.
@@ -1076,7 +1084,7 @@ int cpu_vcpu_nested_hext_csr_rmw(struct vmm_vcpu *vcpu, arch_regs_t *regs,
* H-extension CSRs not allowed in virtual-U mode so forward trap
* as illegal instruction trap to virtual-HS mode.
*/
- if (!(regs->hstatus & HSTATUS_SPVP)) {
+ if (priv_check && !(regs->hstatus & HSTATUS_SPVP)) {
return TRAP_RETURN_ILLEGAL_INSN;
}

@@ -1375,6 +1383,8 @@ int cpu_vcpu_nested_hext_csr_rmw(struct vmm_vcpu *vcpu, arch_regs_t *regs,
}
}

+ cpu_vcpu_nested_update_shmem(vcpu, csr_num, *csr);
+
if (nuke_swtlb) {
cpu_vcpu_nested_swtlb_flush(vcpu, 0, 0);
}
@@ -1382,6 +1392,230 @@ int cpu_vcpu_nested_hext_csr_rmw(struct vmm_vcpu *vcpu, arch_regs_t *regs,
return VMM_OK;
}

+int cpu_vcpu_nested_hext_csr_rmw(struct vmm_vcpu *vcpu, arch_regs_t *regs,
+ unsigned int csr_num, unsigned long *val,
+ unsigned long new_val, unsigned long wr_mask)
+{
+ riscv_stats_priv(vcpu)->nested_hext_csr_rmw++;
+
+ return __cpu_vcpu_nested_hext_csr_rmw(vcpu, regs, TRUE, csr_num,
+ val, new_val, wr_mask);
+}
+
+int cpu_vcpu_nested_setup_shmem(struct vmm_vcpu *vcpu, arch_regs_t *regs,
+ physical_addr_t addr)
+{
+ int rc;
+ u32 reg_flags;
+ physical_size_t availsz;
+ physical_addr_t shmem_hpa;
+ struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);
+
+ /* First unmap shared memory if already available */
+ if (npriv->shmem) {
+ vmm_host_memunmap((virtual_addr_t)npriv->shmem);
+ npriv->shmem = NULL;
+ }
+
+ /* If shared memory address is all ones then do nothing */
+ if (addr == -1UL) {
+ return VMM_OK;
+ }
+ if (addr & ((1UL << SBI_NACL_SHMEM_ADDR_SHIFT) - 1)) {
+ return VMM_EINVALID;
+ }
+
+ /* Get host physical address and attributes of shared memory */
+ rc = vmm_guest_physical_map(vcpu->guest,
+ addr, SBI_NACL_SHMEM_SIZE,
+ &shmem_hpa, &availsz, &reg_flags);
+ if (rc || (availsz < SBI_NACL_SHMEM_SIZE) ||
+ !(reg_flags & VMM_REGION_ISRAM)) {
+ return VMM_ERANGE;
+ }
+
+ /* Map the shared memory */
+ npriv->shmem = (void *)vmm_host_memmap(shmem_hpa, SBI_NACL_SHMEM_SIZE,
+ VMM_MEMORY_FLAGS_NORMAL);
+ if (!npriv->shmem) {
+ return VMM_EIO;
+ }
+
+ /* Finally synchronize CSRs in newly mapped shared memory */
+ cpu_vcpu_nested_sync_csr(vcpu, regs, -1UL);
+
+ return VMM_OK;
+}
+
+void cpu_vcpu_nested_update_shmem(struct vmm_vcpu *vcpu, unsigned int csr_num,
+ unsigned long csr_val)
+{
+ u8 *dbmap;
+ unsigned int cidx;
+ unsigned long *csrs;
+ struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);
+
+ /* If shared memory not available then do nothing */
+ if (!npriv->shmem) {
+ return;
+ }
+ csrs = npriv->shmem + SBI_NACL_SHMEM_CSR_OFFSET;
+ dbmap = npriv->shmem + SBI_NACL_SHMEM_DBITMAP_OFFSET;
+
+ /* Write csr_val in the shared memory */
+ cidx = SBI_NACL_SHMEM_CSR_INDEX(csr_num);
+ csrs[cidx] = vmm_cpu_to_le_long(csr_val);
+
+ /* Clear bit in dirty bitmap */
+ dbmap[cidx >> 3] &= ~(((u8)1) << (cidx & 0x7));
+}
+
+static const unsigned int nested_sync_csrs[] = {
+ CSR_HSTATUS,
+ CSR_HEDELEG,
+ CSR_HIDELEG,
+ CSR_VSTIMECMP,
+ CSR_VSTIMECMPH,
+ CSR_HVIP,
+ CSR_HIE,
+ CSR_HIP,
+ CSR_HGEIP,
+ CSR_HGEIE,
+ CSR_HCOUNTEREN,
+ CSR_HTIMEDELTA,
+#ifndef CONFIG_64BIT
+ CSR_HTIMEDELTAH,
+#endif
+ CSR_HTVAL,
+ CSR_HTINST,
+ CSR_HGATP,
+ CSR_HENVCFG,
+#ifndef CONFIG_64BIT
+ CSR_HENVCFGH,
+#endif
+ CSR_HVICTL,
+ CSR_VSSTATUS,
+ CSR_VSIP,
+ CSR_VSIE,
+ CSR_VSTVEC,
+ CSR_VSSCRATCH,
+ CSR_VSEPC,
+ CSR_VSCAUSE,
+ CSR_VSTVAL,
+ CSR_VSATP,
+};
+
+bool cpu_vcpu_nested_check_shmem(struct vmm_vcpu *vcpu, unsigned int csr_num)
+{
+ u8 *dbmap;
+ unsigned int cidx;
+ struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);
+
+ /* If shared memory not available then not dirty */
+ if (!npriv->shmem) {
+ return FALSE;
+ }
+
+ dbmap = npriv->shmem + SBI_NACL_SHMEM_DBITMAP_OFFSET;
+ cidx = SBI_NACL_SHMEM_CSR_INDEX(csr_num);
+ return (dbmap[cidx >> 3] & (1U << (cidx & 0x7))) ? TRUE : FALSE;
+}
+
+int cpu_vcpu_nested_sync_csr(struct vmm_vcpu *vcpu, arch_regs_t *regs,
+ unsigned long csr_num)
+{
+ unsigned int i, cidx, cnum;
+ unsigned long *csrs, new_val, wr_mask;
+ struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);
+
+ /* Ensure CSR number is a valid HS-mode CSR or -1UL */
+ if ((csr_num != -1UL) &&
+ (((1UL << 12) <= csr_num) || ((csr_num & 0x300) != 0x200))) {
+ return VMM_EINVALID;
+ }
+
+ /* If shared memory not available then fail */
+ if (!npriv->shmem) {
+ return VMM_ENOSYS;
+ }
+ csrs = npriv->shmem + SBI_NACL_SHMEM_CSR_OFFSET;
+
+ /* Sync-up CSRs in shared memory */
+ for (i = 0; i < array_size(nested_sync_csrs); i++) {
+ cnum = nested_sync_csrs[i];
+ if (csr_num != -1UL && csr_num != cnum) {
+ continue;
+ }
+
+ /* Get dirty value of CSR from shared memory */
+ new_val = wr_mask = 0;
+ if (cpu_vcpu_nested_check_shmem(vcpu, cnum)) {
+ wr_mask = -1UL;
+ cidx = SBI_NACL_SHMEM_CSR_INDEX(cnum);
+ new_val = vmm_le_long_to_cpu(csrs[cidx]);
+ }
+
+ /* Update the CSR and shared memory */
+ __cpu_vcpu_nested_hext_csr_rmw(vcpu, regs, FALSE, cnum,
+ NULL, new_val, wr_mask);
+ }
+
+ return VMM_OK;
+}
+
+void cpu_vcpu_nested_prep_sret(struct vmm_vcpu *vcpu, arch_regs_t *regs)
+{
+ int i;
+ unsigned long *src_x, *dst_x;
+ struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);
+
+ /* If shared memory not available then do nothing */
+ if (!npriv->shmem) {
+ return;
+ }
+
+ /* Synchronize all CSRs from shared memory */
+ cpu_vcpu_nested_sync_csr(vcpu, regs, -1UL);
+
+ /* Restore GPRs from shared memory scratch space */
+ for (i = 1; i <= SBI_NACL_SHMEM_SRET_X_LAST; i++) {
+ dst_x = (void *)regs + SBI_NACL_SHMEM_SRET_X(i);
+ src_x = npriv->shmem + SBI_NACL_SHMEM_SRET_OFFSET +
+ SBI_NACL_SHMEM_SRET_X(i);
+ *dst_x = vmm_le_long_to_cpu(*src_x);
+ }
+
+ /*
+ * We may transition virtualization state from OFF to ON
+ * so execute nested autoswap CSR feature.
+ */
+ cpu_vcpu_nested_autoswap(vcpu, regs);
+}
+
+void cpu_vcpu_nested_autoswap(struct vmm_vcpu *vcpu, arch_regs_t *regs)
+{
+ unsigned long tmp, *autoswap;
+ struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);
+
+ /* If shared memory not available then do nothing */
+ if (!npriv->shmem) {
+ return;
+ }
+
+ /* Swap CSRs based on flags */
+ autoswap = npriv->shmem + SBI_NACL_SHMEM_AUTOSWAP_OFFSET;
+ if (vmm_le_long_to_cpu(*autoswap) &
+ SBI_NACL_SHMEM_AUTOSWAP_FLAG_HSTATUS) {
+ autoswap = npriv->shmem + SBI_NACL_SHMEM_AUTOSWAP_OFFSET +
+ SBI_NACL_SHMEM_AUTOSWAP_HSTATUS;
+ __cpu_vcpu_nested_hext_csr_rmw(vcpu, regs,
+ FALSE, CSR_HSTATUS,
+ &tmp, vmm_le_long_to_cpu(*autoswap),
+ -1UL);
+ *autoswap = vmm_cpu_to_le_long(tmp);
+ }
+}
+
int cpu_vcpu_nested_page_fault(struct vmm_vcpu *vcpu,
bool trap_from_smode,
const struct cpu_vcpu_trap *trap,
@@ -1609,6 +1843,7 @@ void cpu_vcpu_nested_set_virt(struct vmm_vcpu *vcpu, struct arch_regs *regs,
bool spvp, bool gva)
{
unsigned long tmp;
+ bool virt_on2off = FALSE;
struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);

/* If H-extension is not available for VCPU then do nothing */
@@ -1683,6 +1918,9 @@ void cpu_vcpu_nested_set_virt(struct vmm_vcpu *vcpu, struct arch_regs *regs,
npriv->vsstatus &= ~SSTATUS_FS;
npriv->vsstatus |= tmp;
npriv->vsstatus = csr_swap(CSR_VSSTATUS, npriv->vsstatus);
+
+ /* Mark that we are transitioning from virt ON to OFF */
+ virt_on2off = TRUE;
}

skip_csr_update:
@@ -1725,6 +1963,18 @@ skip_csr_update:

/* Update virt flag */
npriv->virt = virt;
+
+ /* Extra work post virt ON to OFF transition */
+ if (virt_on2off) {
+ /*
+ * We transitioned virtualization state from ON to OFF
+ * so execute nested autoswap CSR feature.
+ */
+ cpu_vcpu_nested_autoswap(vcpu, regs);
+
+ /* Synchronize CSRs in shared memory */
+ cpu_vcpu_nested_sync_csr(vcpu, regs, -1UL);
+ }
}

void cpu_vcpu_nested_take_vsirq(struct vmm_vcpu *vcpu,
diff --git a/arch/riscv/cpu/generic/cpu_vcpu_trap.c b/arch/riscv/cpu/generic/cpu_vcpu_trap.c
index 4ebce159..0dacbfc0 100644
--- a/arch/riscv/cpu/generic/cpu_vcpu_trap.c
+++ b/arch/riscv/cpu/generic/cpu_vcpu_trap.c
@@ -96,14 +96,14 @@ void cpu_vcpu_redirect_trap(struct vmm_vcpu *vcpu, arch_regs_t *regs,
break;
}

- /* Turn-off nested virtualization for virtual-HS mode */
- cpu_vcpu_nested_set_virt(vcpu, regs, NESTED_SET_VIRT_EVENT_TRAP,
- FALSE, prev_spp, gva);
-
/* Update Guest HTVAL and HTINST */
npriv->htval = trap->htval;
npriv->htinst = trap->htinst;

+ /* Turn-off nested virtualization for virtual-HS mode */
+ cpu_vcpu_nested_set_virt(vcpu, regs, NESTED_SET_VIRT_EVENT_TRAP,
+ FALSE, prev_spp, gva);
+
/* Update Guest supervisor state */
cpu_vcpu_redirect_smode_trap(regs, trap, prev_spp);
}
diff --git a/arch/riscv/cpu/generic/include/arch_regs.h b/arch/riscv/cpu/generic/include/arch_regs.h
index b09d0aa2..3e0d8ceb 100644
--- a/arch/riscv/cpu/generic/include/arch_regs.h
+++ b/arch/riscv/cpu/generic/include/arch_regs.h
@@ -161,6 +161,8 @@ struct riscv_priv_nested {
void *swtlb;
/* Nested shadow page table */
struct mmu_pgtbl *pgtbl;
+ /* Nested shared memory */
+ void *shmem;
/* Nested CSR state */
unsigned long hstatus;
unsigned long hedeleg;
diff --git a/arch/riscv/cpu/generic/include/cpu_vcpu_nested.h b/arch/riscv/cpu/generic/include/cpu_vcpu_nested.h
index 63f6b443..d930750f 100644
--- a/arch/riscv/cpu/generic/include/cpu_vcpu_nested.h
+++ b/arch/riscv/cpu/generic/include/cpu_vcpu_nested.h
@@ -26,6 +26,7 @@

#include <vmm_types.h>

+struct vmm_chardev;
struct vmm_vcpu;
struct cpu_vcpu_trap;
struct arch_regs;
@@ -58,6 +59,27 @@ int cpu_vcpu_nested_hext_csr_rmw(struct vmm_vcpu *vcpu, arch_regs_t *regs,
unsigned int csr_num, unsigned long *val,
unsigned long new_val, unsigned long wr_mask);

+/** Set nested CSR shared memory address */
+int cpu_vcpu_nested_setup_shmem(struct vmm_vcpu *vcpu, arch_regs_t *regs,
+ physical_addr_t addr);
+
+/** Check dirty state of nested CSR value in shared memory */
+bool cpu_vcpu_nested_check_shmem(struct vmm_vcpu *vcpu, unsigned int csr_num);
+
+/** Update nested CSR value in shared memory and clear dirty state */
+void cpu_vcpu_nested_update_shmem(struct vmm_vcpu *vcpu, unsigned int csr_num,
+ unsigned long csr_val);
+
+/** Synchronize nested CSR(s) in shared memory */
+int cpu_vcpu_nested_sync_csr(struct vmm_vcpu *vcpu, arch_regs_t *regs,
+ unsigned long csr_num);
+
+/** Prepare synchronized SRET using shared memory */
+void cpu_vcpu_nested_prep_sret(struct vmm_vcpu *vcpu, arch_regs_t *regs);
+
+/** Autoswap CSRs using shared memory */
+void cpu_vcpu_nested_autoswap(struct vmm_vcpu *vcpu, arch_regs_t *regs);
+
/** Function to handle nested page fault */
int cpu_vcpu_nested_page_fault(struct vmm_vcpu *vcpu,
bool trap_from_smode,
--
2.34.1

Anup Patel

unread,
Jul 1, 2024, 11:01:33 AM7/1/24
to xvisor...@googlegroups.com, Anup Patel
The HFENCE instruction traps from Guest Hypervisor to Host Hypervisor
also add overhead for nested virtualization. This patch extends the
nested virtualization to allow shared memory based access HFENCEs from
the Guest Hypervisor.

Signed-off-by: Anup Patel <apa...@ventanamicro.com>
---
arch/riscv/cpu/generic/cpu_vcpu_nested.c | 121 ++++++++++++++++++
.../cpu/generic/include/cpu_vcpu_nested.h | 4 +
2 files changed, 125 insertions(+)

diff --git a/arch/riscv/cpu/generic/cpu_vcpu_nested.c b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
index 83fc199e..12db30b1 100644
--- a/arch/riscv/cpu/generic/cpu_vcpu_nested.c
+++ b/arch/riscv/cpu/generic/cpu_vcpu_nested.c
@@ -1563,6 +1563,124 @@ int cpu_vcpu_nested_sync_csr(struct vmm_vcpu *vcpu, arch_regs_t *regs,
return VMM_OK;
}

+int cpu_vcpu_nested_sync_hfence(struct vmm_vcpu *vcpu, arch_regs_t *regs,
+ unsigned long entry_num)
+{
+ unsigned long i, p, *entry, hgatp;
+ unsigned long ctrl, type, order, vmid, asid, pnum, pcount;
+ struct riscv_priv_nested *npriv = riscv_nested_priv(vcpu);
+ unsigned long current_vmid =
+ (npriv->hgatp & HGATP_VMID) >> HGATP_VMID_SHIFT;
+ unsigned long first = 0, last = SBI_NACL_SHMEM_HFENCE_ENTRY_MAX - 1;
+
+ /* Ensure entry number is valid */
+ if (entry_num != -1UL) {
+ if (entry_num >= SBI_NACL_SHMEM_HFENCE_ENTRY_MAX) {
+ return VMM_EINVALID;
+ }
+ first = last = entry_num;
+ }
+
+ /* If shared memory not available then fail */
+ if (!npriv->shmem) {
+ return VMM_ENOSYS;
+ }
+
+ /* Iterate over each HFENCE entry */
+ for (i = first; i <= last; i++) {
+ /* Read control word */
+ entry = npriv->shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CTRL(i);
+ ctrl = vmm_le_long_to_cpu(*entry);
+
+ /* Check and control pending bit */
+ if (!(ctrl & SBI_NACL_SHMEM_HFENCE_CTRL_PEND)) {
+ continue;
+ }
+ ctrl &= ~SBI_NACL_SHMEM_HFENCE_CTRL_PEND;
+ *entry = vmm_cpu_to_le_long(ctrl);
+
+ /* Extract remaining control word fields */
+ type = (ctrl >> SBI_NACL_SHMEM_HFENCE_CTRL_TYPE_SHIFT) &
+ SBI_NACL_SHMEM_HFENCE_CTRL_TYPE_MASK;
+ order = (ctrl >> SBI_NACL_SHMEM_HFENCE_CTRL_ORDER_SHIFT) &
+ SBI_NACL_SHMEM_HFENCE_CTRL_ORDER_MASK;
+ order += SBI_NACL_SHMEM_HFENCE_ORDER_BASE;
+ vmid = (ctrl >> SBI_NACL_SHMEM_HFENCE_CTRL_VMID_SHIFT) &
+ SBI_NACL_SHMEM_HFENCE_CTRL_VMID_MASK;
+ asid = ctrl & SBI_NACL_SHMEM_HFENCE_CTRL_ASID_MASK;
+
+ /* Read page address and page count */
+ entry = npriv->shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i);
+ pnum = vmm_le_long_to_cpu(*entry);
+ entry = npriv->shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i);
+ pcount = vmm_le_long_to_cpu(*entry);
+
+ /* Process the HFENCE entry */
+ switch (type) {
+ case SBI_NACL_SHMEM_HFENCE_TYPE_GVMA:
+ cpu_vcpu_nested_swtlb_flush(vcpu, pnum << order,
+ pcount << order);
+ break;
+ case SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_ALL:
+ cpu_vcpu_nested_swtlb_flush(vcpu, 0, 0);
+ break;
+ case SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_VMID:
+ if (current_vmid != vmid) {
+ break;
+ }
+ cpu_vcpu_nested_swtlb_flush(vcpu, pnum << order,
+ pcount << order);
+ break;
+ case SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_VMID_ALL:
+ if (current_vmid != vmid) {
+ break;
+ }
+ cpu_vcpu_nested_swtlb_flush(vcpu, 0, 0);
+ break;
+ case SBI_NACL_SHMEM_HFENCE_TYPE_VVMA:
+ hgatp = mmu_pgtbl_hw_tag(npriv->pgtbl);
+ hgatp = csr_swap(CSR_HGATP, hgatp << HGATP_VMID_SHIFT);
+ if ((PGTBL_PAGE_SIZE / sizeof(arch_pte_t)) < pcount) {
+ __hfence_vvma_all();
+ } else {
+ for (p = pnum; p < (pnum + pcount); p++) {
+ __hfence_vvma_va(p << order);
+ }
+ }
+ csr_write(CSR_HGATP, hgatp);
+ break;
+ case SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ALL:
+ hgatp = mmu_pgtbl_hw_tag(npriv->pgtbl);
+ hgatp = csr_swap(CSR_HGATP, hgatp << HGATP_VMID_SHIFT);
+ __hfence_vvma_all();
+ csr_write(CSR_HGATP, hgatp);
+ break;
+ case SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ASID:
+ hgatp = mmu_pgtbl_hw_tag(npriv->pgtbl);
+ hgatp = csr_swap(CSR_HGATP, hgatp << HGATP_VMID_SHIFT);
+ if ((PGTBL_PAGE_SIZE / sizeof(arch_pte_t)) < pcount) {
+ __hfence_vvma_asid(asid);
+ } else {
+ for (p = pnum; p < (pnum + pcount); p++) {
+ __hfence_vvma_asid_va(p << order, asid);
+ }
+ }
+ csr_write(CSR_HGATP, hgatp);
+ break;
+ case SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ASID_ALL:
+ hgatp = mmu_pgtbl_hw_tag(npriv->pgtbl);
+ hgatp = csr_swap(CSR_HGATP, hgatp << HGATP_VMID_SHIFT);
+ __hfence_vvma_asid(asid);
+ csr_write(CSR_HGATP, hgatp);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return VMM_OK;
+}
+
void cpu_vcpu_nested_prep_sret(struct vmm_vcpu *vcpu, arch_regs_t *regs)
{
int i;
@@ -1577,6 +1695,9 @@ void cpu_vcpu_nested_prep_sret(struct vmm_vcpu *vcpu, arch_regs_t *regs)
/* Synchronize all CSRs from shared memory */
cpu_vcpu_nested_sync_csr(vcpu, regs, -1UL);

+ /* Synchronize all HFENCEs from shared memory */
+ cpu_vcpu_nested_sync_hfence(vcpu, regs, -1UL);
+
/* Restore GPRs from shared memory scratch space */
for (i = 1; i <= SBI_NACL_SHMEM_SRET_X_LAST; i++) {
dst_x = (void *)regs + SBI_NACL_SHMEM_SRET_X(i);
diff --git a/arch/riscv/cpu/generic/include/cpu_vcpu_nested.h b/arch/riscv/cpu/generic/include/cpu_vcpu_nested.h
index d930750f..508548aa 100644
--- a/arch/riscv/cpu/generic/include/cpu_vcpu_nested.h
+++ b/arch/riscv/cpu/generic/include/cpu_vcpu_nested.h
@@ -74,6 +74,10 @@ void cpu_vcpu_nested_update_shmem(struct vmm_vcpu *vcpu, unsigned int csr_num,
int cpu_vcpu_nested_sync_csr(struct vmm_vcpu *vcpu, arch_regs_t *regs,
unsigned long csr_num);

+/** Synchronize nested HFENCEs in shared memory */
+int cpu_vcpu_nested_sync_hfence(struct vmm_vcpu *vcpu, arch_regs_t *regs,
+ unsigned long entry_num);
+
/** Prepare synchronized SRET using shared memory */
void cpu_vcpu_nested_prep_sret(struct vmm_vcpu *vcpu, arch_regs_t *regs);

--
2.34.1

Anup Patel

unread,
Jul 1, 2024, 11:01:36 AM7/1/24
to xvisor...@googlegroups.com, Anup Patel
We implement SBI nested acceleration calls for the Guest/VM so
that traps from Guest Hypervisor to Xvisor can be minimized using
a collabrative approach.

Signed-off-by: Anup Patel <apa...@ventanamicro.com>
---
arch/riscv/cpu/generic/cpu_vcpu_sbi.c | 2 +
arch/riscv/cpu/generic/cpu_vcpu_sbi_nacl.c | 97 ++++++++++++++++++++++
arch/riscv/cpu/generic/objects.mk | 1 +
3 files changed, 100 insertions(+)
create mode 100644 arch/riscv/cpu/generic/cpu_vcpu_sbi_nacl.c

diff --git a/arch/riscv/cpu/generic/cpu_vcpu_sbi.c b/arch/riscv/cpu/generic/cpu_vcpu_sbi.c
index b97a560f..f7763ca8 100644
--- a/arch/riscv/cpu/generic/cpu_vcpu_sbi.c
+++ b/arch/riscv/cpu/generic/cpu_vcpu_sbi.c
@@ -37,6 +37,7 @@ extern const struct cpu_vcpu_sbi_extension vcpu_sbi_base;
extern const struct cpu_vcpu_sbi_extension vcpu_sbi_hsm;
extern const struct cpu_vcpu_sbi_extension vcpu_sbi_dbcn;
extern const struct cpu_vcpu_sbi_extension vcpu_sbi_srst;
+extern const struct cpu_vcpu_sbi_extension vcpu_sbi_nacl;
extern const struct cpu_vcpu_sbi_extension vcpu_sbi_legacy;
extern const struct cpu_vcpu_sbi_extension vcpu_sbi_xvisor;

@@ -48,6 +49,7 @@ static const struct cpu_vcpu_sbi_extension *sbi_exts[] = {
&vcpu_sbi_hsm,
&vcpu_sbi_dbcn,
&vcpu_sbi_srst,
+ &vcpu_sbi_nacl,
&vcpu_sbi_legacy,
&vcpu_sbi_xvisor,
};
diff --git a/arch/riscv/cpu/generic/cpu_vcpu_sbi_nacl.c b/arch/riscv/cpu/generic/cpu_vcpu_sbi_nacl.c
new file mode 100644
index 00000000..d806ae03
--- /dev/null
+++ b/arch/riscv/cpu/generic/cpu_vcpu_sbi_nacl.c
@@ -0,0 +1,97 @@
+/**
+ * Copyright (c) 2022 Ventana Micro Systems Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * @file cpu_vcpu_sbi_nacl.c
+ * @author Anup Patel (apa...@ventanamicro.com)
+ * @brief source of SBI nested accleration extension
+ */
+
+#include <vmm_error.h>
+#include <vmm_macros.h>
+#include <vmm_manager.h>
+#include <vmm_scheduler.h>
+
+#include <cpu_hwcap.h>
+#include <cpu_vcpu_nested.h>
+#include <cpu_vcpu_sbi.h>
+#include <cpu_vcpu_trap.h>
+#include <riscv_sbi.h>
+
+static int vcpu_sbi_nacl_ecall(struct vmm_vcpu *vcpu, unsigned long ext_id,
+ unsigned long func_id, unsigned long *args,
+ struct cpu_vcpu_sbi_return *out)
+{
+ int ret = VMM_OK;
+ arch_regs_t *regs = vmm_scheduler_irq_regs();
+
+ switch (func_id) {
+ case SBI_EXT_NACL_PROBE_FEATURE:
+ switch (args[0]) {
+ case SBI_NACL_FEAT_SYNC_CSR:
+ case SBI_NACL_FEAT_SYNC_HFENCE:
+ case SBI_NACL_FEAT_SYNC_SRET:
+ case SBI_NACL_FEAT_AUTOSWAP_CSR:
+ out->value = 1;
+ break;
+ default:
+ out->value = 0;
+ break;
+ }
+ break;
+ case SBI_EXT_NACL_SET_SHMEM:
+ if (args[0] != -1UL && args[1]) {
+ ret = VMM_ERANGE;
+ break;
+ }
+ ret = cpu_vcpu_nested_setup_shmem(vcpu, regs, args[0]);
+ break;
+ case SBI_EXT_NACL_SYNC_CSR:
+ ret = cpu_vcpu_nested_sync_csr(vcpu, regs, args[0]);
+ break;
+ case SBI_EXT_NACL_SYNC_HFENCE:
+ ret = cpu_vcpu_nested_sync_hfence(vcpu, regs, args[0]);
+ break;
+ case SBI_EXT_NACL_SYNC_SRET:
+ cpu_vcpu_nested_prep_sret(vcpu, regs);
+ /*
+ * Ignore the SRET return value because over here:
+ * 1) nested virt is OFF
+ * 2) hstatus.SPVP == 1
+ */
+ cpu_vcpu_sret_insn(vcpu, regs, 0);
+ out->regs_updated = TRUE;
+ break;
+ default:
+ return SBI_ERR_NOT_SUPPORTED;
+ }
+
+ return cpu_vcpu_sbi_xlate_error(ret);
+}
+
+static unsigned long vcpu_sbi_nacl_probe(struct vmm_vcpu *vcpu)
+{
+ return riscv_isa_extension_available(riscv_priv(vcpu)->isa, h) ? 1 : 0;
+}
+
+const struct cpu_vcpu_sbi_extension vcpu_sbi_nacl = {
+ .name = "nacl",
+ .extid_start = SBI_EXT_NACL,
+ .extid_end = SBI_EXT_NACL,
+ .handle = vcpu_sbi_nacl_ecall,
+ .probe = vcpu_sbi_nacl_probe,
+};
diff --git a/arch/riscv/cpu/generic/objects.mk b/arch/riscv/cpu/generic/objects.mk
index 576603f6..06b249fc 100644
--- a/arch/riscv/cpu/generic/objects.mk
+++ b/arch/riscv/cpu/generic/objects.mk
@@ -99,6 +99,7 @@ cpu-objs-y+= cpu_vcpu_sbi_base.o
cpu-objs-y+= cpu_vcpu_sbi_legacy.o
cpu-objs-y+= cpu_vcpu_sbi_replace.o
cpu-objs-y+= cpu_vcpu_sbi_hsm.o
+cpu-objs-y+= cpu_vcpu_sbi_nacl.o
cpu-objs-y+= cpu_vcpu_sbi_xvisor.o
cpu-objs-y+= cpu_vcpu_switch.o
cpu-objs-y+= cpu_vcpu_timer.o
--
2.34.1

Anup Patel

unread,
Jul 8, 2024, 6:56:13 AM7/8/24
to xvisor...@googlegroups.com, Anup Patel
On Mon, Jul 1, 2024 at 8:30 PM Anup Patel <apa...@ventanamicro.com> wrote:
>
> This series adds RISC-V SBI nested acceleration implementation for
> Xvisor RISC-V.
>
> These patches can also be found in riscv_sbi_nested_v1 branch at:
> https://github.com/avpatel/xvisor-next.git
>
> Anup Patel (8):
> RISC-V: Count the guest page faults redirected to the Guest
> RISC-V: Use bitfields in struct arch_pgflags
> RISC-V: Increase the SWTLB size used for nested virtualization
> RISC-V: Remove redundant timer event from struct riscv_priv_nested
> RISC-V: Add defines for the SBI nested acceleration extension
> RISC-V: Extend nested virtualization for shared memory based CSR
> access
> RISC-V: Extend nested virtualization for shared memory based HFENCE
> RISC-V: Implement SBI nested acceleration extension

Applied this series to the xvisor-next repo.

Thanks,
Anup

>
> arch/riscv/cpu/generic/cpu_vcpu_helper.c | 37 +-
> arch/riscv/cpu/generic/cpu_vcpu_nested.c | 423 ++++++++++++++++--
> arch/riscv/cpu/generic/cpu_vcpu_sbi.c | 6 +-
> arch/riscv/cpu/generic/cpu_vcpu_sbi_nacl.c | 97 ++++
> arch/riscv/cpu/generic/cpu_vcpu_trap.c | 8 +-
> arch/riscv/cpu/generic/include/arch_mmu.h | 18 +-
> arch/riscv/cpu/generic/include/arch_regs.h | 7 +-
> .../cpu/generic/include/cpu_vcpu_nested.h | 26 ++
> arch/riscv/cpu/generic/include/riscv_sbi.h | 103 +++++
> arch/riscv/cpu/generic/objects.mk | 1 +
> 10 files changed, 666 insertions(+), 60 deletions(-)
> create mode 100644 arch/riscv/cpu/generic/cpu_vcpu_sbi_nacl.c
>
> --
> 2.34.1
>
> --
> You received this message because you are subscribed to the Google Groups "Xvisor Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to xvisor-devel...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/xvisor-devel/20240701150044.650005-1-apatel%40ventanamicro.com.
Reply all
Reply to author
Forward
0 new messages