Files
acrn-hypervisor/hypervisor/arch/riscv/guest/vsbi.c
Haoyu Tang b8db76fe55 hv: riscv add vSBI IPI extension support
Implement the SBI IPI (Inter-Processor Interrupt) extension to enable
guest VMs to send software interrupts between virtual CPUs.

The implementation handles the SBI_IPI_SEND_IPI function call, which
allows a guest to target one or more vCPUs using either:
- A mask (bitmap of target harts relative to a base hart ID)
- Broadcast mode (when mask_base is UINT64_MAX)

The IPI is delivered by asserting the VS-level software interrupt
(VSSIP, bit 2) on each target vCPU. Proper validation is performed
to ensure hart IDs are within valid range and all masked harts exist.

Tracked-On: #8851
Signed-off-by: Haoyu Tang <haoyu.tang@intel.com>
Acked-by: Wang Yu1 <yu1.wang@intel.com>
2025-12-26 07:57:51 +08:00

128 lines
3.2 KiB
C

/*
* Copyright (C) 2018-2025 Intel Corporation.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Author: Haicheng Li <haicheng.li@intel.com>
* Yifan Liu <yifan1.liu@intel.com>
*
* Re-written from OpenSBI sbi_ecall.c
* The original code is licensed under BSD-2-Clause
*/
#include <vcpu.h>
#include <vcpu.h>
#include <vm.h>
#include <logmsg.h>
#include <asm/sbi.h>
#include <asm/guest/vsbi.h>
const struct acrn_vsbi_extension *vcpu_find_extension(struct acrn_vcpu *vcpu, uint64_t eid)
{
const struct acrn_vsbi_extension *e, *ret = NULL;
struct acrn_vm *vm = vcpu->vm;
int i;
for (i = 0; i < vm->arch_vm.n_vsbi_exts; i++) {
e = vm->arch_vm.vsbi_exts[i];
if ((eid >= e->eid_start) && (eid <= e->eid_end)) {
ret = e;
break;
}
}
return ret;
}
int32_t vsbi_exit_handler(struct acrn_vcpu *vcpu)
{
struct cpu_regs *regs = &(vcpu->arch.regs);
uint64_t args[6];
uint64_t eid = regs->a7, fid = regs->a6;
int32_t ret = SBI_ERR_NOT_SUPPORTED;
struct vsbi_ret out = { 0 };
const struct acrn_vsbi_extension *e;
args[0] = regs->a0;
args[1] = regs->a1;
args[2] = regs->a2;
args[3] = regs->a3;
args[4] = regs->a4;
args[5] = regs->a5;
e = vcpu_find_extension(vcpu, eid);
if (e && e->handler) {
pr_dbg("vsbi: eid: 0x%x fid: 0x%x, args 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
eid, fid, args[0], args[1], args[2], args[3], args[4], args[5]);
ret = e->handler(vcpu, eid, fid, args, &out);
} else {
pr_err("Unsupported ecall request: eid 0x%x fid 0x%x", eid, fid);
}
if (!out.vcpu_retain_pc) {
regs->epc += 4;
}
regs->a0 = ret;
regs->a1 = out.value;
return 0;
}
extern const struct acrn_vsbi_extension vsbi_ext_base;
extern const struct acrn_vsbi_extension vsbi_ext_hsm;
extern const struct acrn_vsbi_extension vsbi_ext_srst;
extern const struct acrn_vsbi_extension vsbi_ext_timer;
extern const struct acrn_vsbi_extension vsbi_ext_acrn;
extern const struct acrn_vsbi_extension vsbi_ext_dbcn;
extern const struct acrn_vsbi_extension vsbi_ext_ipi;
static const struct acrn_vsbi_extension *vsbi_extensions[MAX_NUM_SUPPORTED_VSBI_EXT] = {
&vsbi_ext_base,
&vsbi_ext_hsm,
&vsbi_ext_srst,
&vsbi_ext_acrn,
&vsbi_ext_dbcn,
&vsbi_ext_timer,
&vsbi_ext_ipi,
};
void init_vsbi(struct acrn_vm *vm)
{
uint16_t i;
int32_t ret;
const struct acrn_vsbi_extension *e;
for (i = 0; (i < MAX_NUM_SUPPORTED_VSBI_EXT) && (vsbi_extensions[i] != NULL); i++) {
e = vsbi_extensions[i];
/* Unconditionally register extension if no probe method is provided.
* if probe method is provided, register only when probe success.
*/
if (e->probe == NULL) {
vm->arch_vm.vsbi_exts[vm->arch_vm.n_vsbi_exts++] = e;
} else {
ret = e->probe(vm);
if (ret == 0) {
vm->arch_vm.vsbi_exts[vm->arch_vm.n_vsbi_exts++] = e;
} else if (ret != -ENOSYS) {
pr_err("Failed to register %s to VM%d, ret: %d", e->name, vm->vm_id, ret);
} else {
/* hide extension from this vm */
}
}
}
if (is_service_vm(vm)) {
/* pass machine IDs from SBI to SOS */
vm->arch_vm.mvendorid = sbi_get_mvendorid();
vm->arch_vm.marchid = sbi_get_marchid();
vm->arch_vm.mimpid = sbi_get_mimpid();
} else {
/* set dummy machine IDs for guest VMs */
vm->arch_vm.mvendorid = VSBI_ACRN_MVENDORID;
vm->arch_vm.marchid = VSBI_ACRN_MARCHID;
vm->arch_vm.mimpid = VSBI_ACRN_MIMPID;
}
}