xen/riscv: introduce vSBI extension framework

Introduce 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@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Oleksii Kurochko authored and Jan Beulich committed 2025-12-29 09:37:14 +01:00
1 parent 62cb3c7510
commit e717a5a4ae
10 files changed
+116

No files matched your search

+1
View File
@@ -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 $< $@
+6
View File
@@ -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)
+1
View File
@@ -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;
};
+31
View File
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef ASM_RISCV_VSBI_H
#define ASM_RISCV_VSBI_H
struct cpu_user_regs;
struct vsbi_ext {
const char *name;
unsigned long eid_start;
unsigned long eid_end;
int (*handler)(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 cpu_user_regs *regs);
const struct vsbi_ext *vsbi_find_extension(unsigned long eid);
void check_vsbi_ext_ranges(void);
#endif
+1
View File
@@ -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));
+3
View File
@@ -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.
+8
View File
@@ -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(cpu_regs);
break;
case CAUSE_ILLEGAL_INSTRUCTION:
if ( do_bug_frame(cpu_regs, pc) >= 0 )
{
+1
View File
@@ -0,0 +1 @@
obj-y += core.o
+57
View File
@@ -0,0 +1,57 @@
/* 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)
{
for ( const struct vsbi_ext *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 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(eid, fid, regs);
else
{
gprintk(XENLOG_ERR, "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;
}
+7
View File
@@ -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);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.