From 0d630e8f37abb5ece36d615a27f6f4e9cb354c39 Mon Sep 17 00:00:00 2001 From: Haicheng Li Date: Tue, 2 Sep 2025 11:33:32 +0800 Subject: [PATCH] hv: ipi: riscv: implement IPI using SBI interface This patch implements the IPI for RISC-V using SBI interface. There is no common IPI concept abstracted, due to the following reasons: - RISC-V: Software delivers an IPI to target CPUs via software interrupts. The interrupt number is fixed for each privilege mode (e.g., Supervisor Software Interrupt = IRQ 1, Machine Software Interrupt = IRQ 3). The actual purpose of the IPI is indicated by an IPI message type, which is a software-level concept. When the IPI is received, the target CPU must check the message type to determine the required action. - x86: Software delivers an IPI to target CPUs using a specific vector number. During CPU initialization, software can assign dedicated vectors for particular purposes. When the IPI is received, the target CPU could directly invoke the handler bound to that vector. Each architecture provides its own IPI implementation, and other SW modules directly call these arch-specific functions. ------ Notes: * To ensure RISC-V builds pass, an empty `include/arch/riscv/asm/cpu.h` is added since `debug/logmsg.h` includes `asm/cpu.h`. * Implemented IPI functionality using the SBI IPI Extension (EID #0x735049). Legacy SBI extensions are not supported in ACRN. ---------- Changelog: * Updated commit message and code comments to state explicitly that legacy SBI extensions are not supported in ACRN. * Refined the prototype of sbi_send_ipi() to align with the SBI spec: From: int64_t sbi_send_ipi(uint64_t mask) To: int64_t sbi_send_ipi(uint64_t mask, uint64_t mask_base) In ACRN it is invoked as sbi_send_ipi(dest_mask, 0UL), with mask_base set to 0UL. * Renamed send_single_ipi() and send_dest_ipi_mask() to arch_send_single_ipi() and arch_send_dest_ipi_mask() respectively. Tracked-On: #8786 Signed-off-by: Haicheng Li Co-developed-by: Shiqing Gao Signed-off-by: Shiqing Gao Acked-by: Wang, Yu1 --- hypervisor/arch/riscv/Makefile | 1 + hypervisor/arch/riscv/sbi.c | 45 +++++++++++++++++++++++++ hypervisor/include/arch/riscv/asm/cpu.h | 0 hypervisor/include/arch/riscv/asm/irq.h | 15 +++++++++ hypervisor/include/arch/riscv/asm/sbi.h | 3 ++ 5 files changed, 64 insertions(+) create mode 100644 hypervisor/include/arch/riscv/asm/cpu.h create mode 100644 hypervisor/include/arch/riscv/asm/irq.h diff --git a/hypervisor/arch/riscv/Makefile b/hypervisor/arch/riscv/Makefile index 54f0c6517..d52cbec11 100644 --- a/hypervisor/arch/riscv/Makefile +++ b/hypervisor/arch/riscv/Makefile @@ -29,6 +29,7 @@ HOST_S_SRCS += arch/riscv/dummy_entry.S # HV host C sources HOST_C_SRCS += arch/riscv/dummy.c +HOST_C_SRCS += arch/riscv/sbi.c # Virtual platform assembly sources VP_S_SRCS += diff --git a/hypervisor/arch/riscv/sbi.c b/hypervisor/arch/riscv/sbi.c index 7834b8a77..73a43c7df 100644 --- a/hypervisor/arch/riscv/sbi.c +++ b/hypervisor/arch/riscv/sbi.c @@ -9,6 +9,7 @@ #include #include +#include /** * An ECALL is used as the control transfer instruction between the @@ -57,3 +58,47 @@ static sbiret sbi_ecall(uint64_t arg0, uint64_t arg1, uint64_t arg2, return ret; } + +/** + * Implemented IPI functionality using the SBI IPI Extension (EID #0x735049). + * Legacy SBI extensions are not supported in ACRN. + */ +static int64_t sbi_send_ipi(uint64_t mask, uint64_t mask_base) +{ + sbiret ret = sbi_ecall(mask, mask_base, 0UL, 0UL, 0UL, 0UL, SBI_IPI_FID_SEND_IPI, SBI_EID_IPI); + + if (ret.error != SBI_SUCCESS) { + pr_err("%s: Failed to send IPI by SBI, error code: %lx", __func__, ret.error); + } + + return ret.error; +} + +/** + * msg_type is currently unused. + * + * At present, only IPI_NOTIFY_CPU is supported, covering two use cases: + * - SMP call + * - Kick pCPU out of non-root mode + * + * Callers should invoke this function with: + * arch_send_single_ipi(pcpu_id, IPI_NOTIFY_CPU); + * + * msg_type is retained for future extensions and to stay aligned with + * the function prototype used on other architectures (e.g. x86). + */ +void arch_send_single_ipi(uint16_t pcpu_id, __unused uint32_t msg_type) +{ + sbi_send_ipi((1UL << pcpu_id), 0UL); +} + +/** + * Similar to arch_send_single_ipi() regards to msg_type. + * + * Callers should invoke this function with: + * arch_send_dest_ipi_mask(dest_mask, IPI_NOTIFY_CPU); + */ +void arch_send_dest_ipi_mask(uint64_t dest_mask, __unused uint32_t msg_type) +{ + sbi_send_ipi(dest_mask, 0UL); +} diff --git a/hypervisor/include/arch/riscv/asm/cpu.h b/hypervisor/include/arch/riscv/asm/cpu.h new file mode 100644 index 000000000..e69de29bb diff --git a/hypervisor/include/arch/riscv/asm/irq.h b/hypervisor/include/arch/riscv/asm/irq.h new file mode 100644 index 000000000..880db7d0d --- /dev/null +++ b/hypervisor/include/arch/riscv/asm/irq.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2023-2025 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Authors: + * Haicheng Li + */ + +#ifndef RISCV_IRQ_H +#define RISCV_IRQ_H + +#define IPI_NOTIFY_CPU 0 + +#endif /* RISCV_IRQ_H */ diff --git a/hypervisor/include/arch/riscv/asm/sbi.h b/hypervisor/include/arch/riscv/asm/sbi.h index b97f49bc3..87c7acc92 100644 --- a/hypervisor/include/arch/riscv/asm/sbi.h +++ b/hypervisor/include/arch/riscv/asm/sbi.h @@ -97,4 +97,7 @@ typedef struct { }; } sbiret; +void arch_send_single_ipi(uint16_t pcpu_id, __unused uint32_t msg_type); +void arch_send_dest_ipi_mask(uint64_t dest_mask, __unused uint32_t msg_type); + #endif /* RISCV_SBI_H */