From 53154763bc480f7840de68c074c60b834597ac53 Mon Sep 17 00:00:00 2001 From: Ivan Velickovic Date: Tue, 3 Sep 2024 20:18:38 +1000 Subject: [PATCH] Add support for custom SMC SiP handler Signed-off-by: Ivan Velickovic --- include/libvmm/arch/aarch64/smc.h | 19 +++++++- src/arch/aarch64/fault.c | 2 +- src/arch/aarch64/smc.c | 79 ++++++++++++++++++++++++++++++- 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/include/libvmm/arch/aarch64/smc.h b/include/libvmm/arch/aarch64/smc.h index bc5e6abf2..752a20868 100644 --- a/include/libvmm/arch/aarch64/smc.h +++ b/include/libvmm/arch/aarch64/smc.h @@ -13,7 +13,24 @@ #include /* SMC vCPU fault handler */ -bool handle_smc(size_t vcpu_id, uint32_t hsr); +bool smc_handle(size_t vcpu_id, uint32_t hsr); + +/* + * A custom handler for SMC SiP calls can be registered. + * By default SiP calls are not handled. + * Note only one handler can be registered at a given time. + * smc_register_sip_handler returns false if a handler already exists. + */ +typedef bool (*smc_sip_handler_t)(size_t vcpu_id, seL4_UserContext *regs, size_t fn_number); +bool smc_register_sip_handler(smc_sip_handler_t handler); + +#if defined(CONFIG_ALLOW_SMC_CALLS) +/* + * Handle SMC SiP calls simply by forwarding the arguments to seL4 to perform + * and placing the response registers into the guest's TCB registers. + */ +bool smc_sip_forward(size_t vcpu, seL4_UserContext *regs, size_t fn_number); +#endif /* Helper functions */ void smc_set_return_value(seL4_UserContext *u, uint64_t val); diff --git a/src/arch/aarch64/fault.c b/src/arch/aarch64/fault.c index f40a3ded6..dca56d1d1 100644 --- a/src/arch/aarch64/fault.c +++ b/src/arch/aarch64/fault.c @@ -220,7 +220,7 @@ bool fault_handle_vcpu_exception(size_t vcpu_id) uint64_t hsr_ec_class = HSR_EXCEPTION_CLASS(hsr); switch (hsr_ec_class) { case HSR_SMC_64_EXCEPTION: - return handle_smc(vcpu_id, hsr); + return smc_handle(vcpu_id, hsr); case HSR_WFx_EXCEPTION: // If we get a WFI exception, we just do nothing in the VMM. return true; diff --git a/src/arch/aarch64/smc.c b/src/arch/aarch64/smc.c index cd305d5be..04b5ecff9 100644 --- a/src/arch/aarch64/smc.c +++ b/src/arch/aarch64/smc.c @@ -8,6 +8,9 @@ #include #include #include +#include + +// #define DEBUG_SMC // Values in this file are taken from: // SMC CALLING CONVENTION @@ -90,8 +93,77 @@ static void smc_set_arg(seL4_UserContext *u, size_t arg, size_t val) } } +static void dump_smc_request(seL4_ARM_SMCContext *request) { + LOG_VMM("SMC forward dump request:\n"); + LOG_VMM(" x0: 0x%lx\n", request->x0); + LOG_VMM(" x1: 0x%lx\n", request->x1); + LOG_VMM(" x2: 0x%lx\n", request->x2); + LOG_VMM(" x3: 0x%lx\n", request->x3); + LOG_VMM(" x4: 0x%lx\n", request->x4); + LOG_VMM(" x5: 0x%lx\n", request->x5); + LOG_VMM(" x6: 0x%lx\n", request->x6); + LOG_VMM(" x7: 0x%lx\n", request->x7); +} + +static void dump_smc_response(seL4_ARM_SMCContext *response) { + LOG_VMM("SMC forward dump response:\n"); + LOG_VMM(" x0: 0x%lx\n", response->x0); + LOG_VMM(" x1: 0x%lx\n", response->x1); + LOG_VMM(" x2: 0x%lx\n", response->x2); + LOG_VMM(" x3: 0x%lx\n", response->x3); + LOG_VMM(" x4: 0x%lx\n", response->x4); + LOG_VMM(" x5: 0x%lx\n", response->x5); + LOG_VMM(" x6: 0x%lx\n", response->x6); + LOG_VMM(" x7: 0x%lx\n", response->x7); +} + +#if defined(CONFIG_ALLOW_SMC_CALLS) +bool smc_sip_forward(size_t vcpu_id, seL4_UserContext *regs, size_t fn_number) +{ + seL4_ARM_SMCContext request; + seL4_ARM_SMCContext response; + + request.x0 = regs->x0; request.x1 = regs->x1; + request.x2 = regs->x2; request.x3 = regs->x3; + request.x4 = regs->x4; request.x5 = regs->x5; + request.x6 = regs->x6; request.x7 = regs->x7; + +#if defined(DEBUG_SMC) + dump_smc_request(&request); +#endif + + microkit_arm_smc_call(&request, &response); + +#if defined(DEBUG_SMC) + dump_smc_response(&response); +#endif + + regs->x0 = response.x0; regs->x1 = response.x1; + regs->x2 = response.x2; regs->x3 = response.x3; + regs->x4 = response.x4; regs->x5 = response.x5; + regs->x6 = response.x6; regs->x7 = response.x7; + + bool success = fault_advance_vcpu(vcpu_id, regs); + assert(success); + + return success; +} +#endif + +static smc_sip_handler_t smc_sip_handler = NULL; + +bool smc_register_sip_handler(smc_sip_handler_t handler) { + if (smc_sip_handler) { + LOG_VMM_ERR("SMC SiP handler already registered\n"); + return false; + } + smc_sip_handler = handler; + + return true; +} + // @ivanv: print out which SMC call as a string we can't handle. -bool handle_smc(size_t vcpu_id, uint32_t hsr) +bool smc_handle(size_t vcpu_id, uint32_t hsr) { // @ivanv: An optimisation to be made is to store the TCB registers so we don't // end up reading them multiple times @@ -109,6 +181,11 @@ bool handle_smc(size_t vcpu_id, uint32_t hsr) } LOG_VMM_ERR("Unhandled SMC: standard service call %lu\n", fn_number); break; + case SMC_CALL_SIP_SERVICE: + if (smc_sip_handler) { + return smc_sip_handler(vcpu_id, ®s, fn_number); + } + /* If we don't have a SiP handler registered, drop to the default case. */ default: LOG_VMM_ERR("Unhandled SMC: unknown value service: 0x%lx, function number: 0x%lx\n", service, fn_number); break;