[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 1/3] xen/riscv: introduce vSBI extension framework



This commit introduces support for handling virtual SBI extensions in Xen.

The changes include:
- Added new vsbi/core.c and vsbi.h files to implement virtual SBI extension
  handling.
- Modified traps.c to handle CAUSE_VIRTUAL_SUPERVISOR_ECALL by calling
  vsbi_handle_ecall() when the trap originates from VS-mode.
- Updated xen.lds.S to include a new .vsbi.exts section for virtual SBI
  extension data.
- Updated Makefile to include the new vsbi/ directory in the build.
- Add hstatus register to struct cpu_user_regs as it is needed for
  a check that CAUSE_VIRTUAL_SUPERVISOR_ECALL happens from VS-mode.
  Also, add storing/restoring of hstatus register in handle_trap().
- Introduce vsbi_find_extension() to check if vsbi extension is supported
  by Xen. For now it is called only inside vsbi/core.c, but in future
  it is going to be called from other files.
- Introduce check_vsbi_ext_ranges() to check if there EIDs ranges
  overlapping between extensions.

The implementation allows for registration and handling of SBI
extensions via a new vsbi_ext structure and ".vsbi.exts" section,
enabling extensible virtual SBI support for RISC-V guests.

Note: All EIDs are printed in the format #%#lx and all FIDs in #%#lu, as
the SBI spec uses these formats. Printing them this way makes it easier to
search for them in the SBI spec.

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
---
Changes in v2:
 - s/struct regs/struct cpu_user_regs.
 - s/handle/handler.
 - Drop extid_ prefix inside VSBI_EXT_START().
 - use BUG_ON() instead of panic to be sure that 
   CAUSE_VIRTUAL_SUPERVISOR_ECALL comes from VS-mode.
 - s/ext_id/eid for vsbi_find_extension().
 - Add the comment above VSBI_EXT_START about [start,end] range.
 - Drop check "&& ext->handler" in vsbi_handle_ecall() as it isn't
   be so that handler() isn't provided.
 - s/vsbi.c/core.c
 - s/vsbi_ext/ext for local variable inside vsbi_find_extension().
 - Update the commit message: add a note about FID and EID printing formats,
   add some information about vsbo_find_extension() function, and add info
   about check_vsbi_ext_ranges().
 - Introduce check_vsbi_ext_ranges() to be sure that there is no overlapping
   in EIDs range(s).
 - Add storing/restoring of hstatus register in handle_trap()[entry.S].
---
 xen/arch/riscv/Makefile                |  1 +
 xen/arch/riscv/entry.S                 |  6 +++
 xen/arch/riscv/include/asm/processor.h |  1 +
 xen/arch/riscv/include/asm/vsbi.h      | 32 +++++++++++++++
 xen/arch/riscv/riscv64/asm-offsets.c   |  1 +
 xen/arch/riscv/setup.c                 |  3 ++
 xen/arch/riscv/traps.c                 |  8 ++++
 xen/arch/riscv/vsbi/Makefile           |  1 +
 xen/arch/riscv/vsbi/core.c             | 56 ++++++++++++++++++++++++++
 xen/arch/riscv/xen.lds.S               |  7 ++++
 10 files changed, 116 insertions(+)
 create mode 100644 xen/arch/riscv/include/asm/vsbi.h
 create mode 100644 xen/arch/riscv/vsbi/Makefile
 create mode 100644 xen/arch/riscv/vsbi/core.c

diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
index 9dde693db4..87c1148b00 100644
--- a/xen/arch/riscv/Makefile
+++ b/xen/arch/riscv/Makefile
@@ -20,6 +20,7 @@ obj-y += time.o
 obj-y += traps.o
 obj-y += vmid.o
 obj-y += vm_event.o
+obj-y += vsbi/
 
 $(TARGET): $(TARGET)-syms
        $(OBJCOPY) -O binary -S $< $@
diff --git a/xen/arch/riscv/entry.S b/xen/arch/riscv/entry.S
index 4db818ba8d..202a35fb03 100644
--- a/xen/arch/riscv/entry.S
+++ b/xen/arch/riscv/entry.S
@@ -48,11 +48,17 @@ save_to_stack:
         csrr    t0, CSR_SSTATUS
         REG_S   t0, CPU_USER_REGS_SSTATUS(sp)
 
+        csrr    t0, CSR_HSTATUS
+        REG_S   t0, CPU_USER_REGS_HSTATUS(sp)
+
         mv      a0, sp
         call    do_trap
 
 restore_registers:
         /* Restore stack_cpu_regs */
+        REG_L  t0, CPU_USER_REGS_HSTATUS(sp)
+        csrw   CSR_HSTATUS, t0
+
         REG_L   t0, CPU_USER_REGS_SEPC(sp)
         csrw    CSR_SEPC, t0
         REG_L   t0, CPU_USER_REGS_SSTATUS(sp)
diff --git a/xen/arch/riscv/include/asm/processor.h 
b/xen/arch/riscv/include/asm/processor.h
index 2502045642..6b89df4a2d 100644
--- a/xen/arch/riscv/include/asm/processor.h
+++ b/xen/arch/riscv/include/asm/processor.h
@@ -49,6 +49,7 @@ struct cpu_user_regs
     unsigned long t6;
     unsigned long sepc;
     unsigned long sstatus;
+    unsigned long hstatus;
     /* pointer to previous stack_cpu_regs */
     unsigned long pregs;
 };
diff --git a/xen/arch/riscv/include/asm/vsbi.h 
b/xen/arch/riscv/include/asm/vsbi.h
new file mode 100644
index 0000000000..47a38dce02
--- /dev/null
+++ b/xen/arch/riscv/include/asm/vsbi.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier:  GPL-2.0-only */
+
+#ifndef ASM_RISCV_VSBI_H
+#define ASM_RISCV_VSBI_H
+
+struct cpu_user_regs;
+struct vcpu;
+
+struct vsbi_ext {
+    const char *name;
+    unsigned long eid_start;
+    unsigned long eid_end;
+    int (*handler)(struct vcpu *vcpu, unsigned long eid,
+                   unsigned long fid, struct cpu_user_regs *regs);
+};
+
+/* Ranges (start and end) are inclusive within an extension */
+#define VSBI_EXT(ext, start, end, handle)           \
+static const struct vsbi_ext vsbi_ext_##ext __used  \
+__section(".vsbi.exts") = {                         \
+    .name = #ext,                                   \
+    .eid_start = start,                             \
+    .eid_end = end,                                 \
+    .handler = handle,                              \
+};
+
+void vsbi_handle_ecall(struct vcpu *vcpu, struct cpu_user_regs *regs);
+const struct vsbi_ext *vsbi_find_extension(unsigned long eid);
+
+void check_vsbi_ext_ranges(void);
+
+#endif
diff --git a/xen/arch/riscv/riscv64/asm-offsets.c 
b/xen/arch/riscv/riscv64/asm-offsets.c
index 3b5daf3b36..472cced4f8 100644
--- a/xen/arch/riscv/riscv64/asm-offsets.c
+++ b/xen/arch/riscv/riscv64/asm-offsets.c
@@ -49,6 +49,7 @@ void asm_offsets(void)
     OFFSET(CPU_USER_REGS_T6, struct cpu_user_regs, t6);
     OFFSET(CPU_USER_REGS_SEPC, struct cpu_user_regs, sepc);
     OFFSET(CPU_USER_REGS_SSTATUS, struct cpu_user_regs, sstatus);
+    OFFSET(CPU_USER_REGS_HSTATUS, struct cpu_user_regs, hstatus);
     OFFSET(CPU_USER_REGS_PREGS, struct cpu_user_regs, pregs);
     BLANK();
     DEFINE(PCPU_INFO_SIZE, sizeof(struct pcpu_info));
diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c
index 8f46f1a1de..9b4835960d 100644
--- a/xen/arch/riscv/setup.c
+++ b/xen/arch/riscv/setup.c
@@ -26,6 +26,7 @@
 #include <asm/sbi.h>
 #include <asm/setup.h>
 #include <asm/traps.h>
+#include <asm/vsbi.h>
 
 /* Xen stack for bringing up the first CPU. */
 unsigned char __initdata cpu0_boot_stack[STACK_SIZE]
@@ -110,6 +111,8 @@ void __init noreturn start_xen(unsigned long bootcpu_id,
 
     end_boot_allocator();
 
+    check_vsbi_ext_ranges();
+
     /*
      * The memory subsystem has been initialized, we can now switch from
      * early_boot -> boot.
diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c
index f061004d83..5c3d1988d7 100644
--- a/xen/arch/riscv/traps.c
+++ b/xen/arch/riscv/traps.c
@@ -15,6 +15,7 @@
 #include <asm/processor.h>
 #include <asm/riscv_encoding.h>
 #include <asm/traps.h>
+#include <asm/vsbi.h>
 
 /*
  * Initialize the trap handling.
@@ -114,6 +115,13 @@ void do_trap(struct cpu_user_regs *cpu_regs)
 
     switch ( cause )
     {
+    case CAUSE_VIRTUAL_SUPERVISOR_ECALL:
+        /* CAUSE_VIRTUAL_SUPERVISOR_ECALL should come from VS-mode */
+        BUG_ON(!(cpu_regs->hstatus & HSTATUS_SPV));
+
+        vsbi_handle_ecall(current, cpu_regs);
+        break;
+
     case CAUSE_ILLEGAL_INSTRUCTION:
         if ( do_bug_frame(cpu_regs, pc) >= 0 )
         {
diff --git a/xen/arch/riscv/vsbi/Makefile b/xen/arch/riscv/vsbi/Makefile
new file mode 100644
index 0000000000..820eb10ac2
--- /dev/null
+++ b/xen/arch/riscv/vsbi/Makefile
@@ -0,0 +1 @@
+obj-y += core.o
diff --git a/xen/arch/riscv/vsbi/core.c b/xen/arch/riscv/vsbi/core.c
new file mode 100644
index 0000000000..5ac4fee379
--- /dev/null
+++ b/xen/arch/riscv/vsbi/core.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/sched.h>
+
+#include <asm/processor.h>
+#include <asm/sbi.h>
+#include <asm/vsbi.h>
+
+extern const struct vsbi_ext _svsbi_exts[], _evsbi_exts[];
+
+void __init check_vsbi_ext_ranges(void)
+{
+    for ( const struct vsbi_ext *a = _svsbi_exts; a != _evsbi_exts; a++ )
+        for ( const struct vsbi_ext *b = a + 1; b != _evsbi_exts; b++ )
+            if ( !(a->eid_end < b->eid_start || b->eid_end < a->eid_start) )
+                panic("EID range overlap detected: "
+                      "%s:[#%#lx..#%#lx] vs %s:[#%#lx..#%#lx]\n",
+                      a->name, a->eid_start, a->eid_end,
+                      b->name, b->eid_start, b->eid_end);
+}
+
+const struct vsbi_ext *vsbi_find_extension(unsigned long eid)
+{
+    const struct vsbi_ext *ext;
+
+    for ( ext = _svsbi_exts; ext != _evsbi_exts; ext++ )
+        if ( (eid >= ext->eid_start) && (eid <= ext->eid_end) )
+            return ext;
+
+    return NULL;
+}
+
+void vsbi_handle_ecall(struct vcpu *vcpu, struct cpu_user_regs *regs)
+{
+    const unsigned long eid = regs->a7;
+    const unsigned long fid = regs->a6;
+    const struct vsbi_ext *ext = vsbi_find_extension(eid);
+    int ret;
+
+    if ( ext )
+        ret = ext->handler(vcpu, eid, fid, regs);
+    else
+    {
+        printk("Unsupported Guest SBI EID #%#lx, FID #%lu\n", eid, regs->a1);
+        ret = SBI_ERR_NOT_SUPPORTED;
+    }
+
+    /*
+     * The ecall instruction is not part of the RISC-V C extension (compressed
+     * instructions), so it is always 4 bytes long. Therefore, it is safe to
+     * use a fixed length of 4 bytes instead of reading guest memory to
+     * determine the instruction length.
+     */
+    regs->sepc += 4;
+    regs->a0 = ret;
+}
diff --git a/xen/arch/riscv/xen.lds.S b/xen/arch/riscv/xen.lds.S
index 45d2e053d0..331a7d63d3 100644
--- a/xen/arch/riscv/xen.lds.S
+++ b/xen/arch/riscv/xen.lds.S
@@ -61,6 +61,13 @@ SECTIONS
         __note_gnu_build_id_end = .;
     } :note :text
     #endif
+
+    . = ALIGN(POINTER_ALIGN);
+    DECL_SECTION(.vsbi.exts) {
+        _svsbi_exts = .;
+        *(.vsbi.exts)
+        _evsbi_exts = .;
+    } :text
     _erodata = .;                /* End of read-only data */
 
     . = ALIGN(PAGE_SIZE);
-- 
2.52.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.