| /* |
| * Copyright 2020, Data61 |
| * Commonwealth Scientific and Industrial Research Organisation (CSIRO) |
| * ABN 41 687 119 230. |
| * |
| * This software may be distributed and modified according to the terms of |
| * the BSD 2-Clause license. Note that NO WARRANTY is provided. |
| * See "LICENSE_BSD2.txt" for details. |
| * |
| * @TAG(DATA61_BSD) |
| */ |
| |
| |
| #include <sel4vm/guest_vm.h> |
| #include <sel4vm/arch/guest_arm_context.h> |
| |
| #include "smc.h" |
| #include "psci.h" |
| |
| static smc_call_id_t smc_get_call(uintptr_t func_id) |
| { |
| seL4_Word service = ((func_id >> SMC_SERVICE_CALL_SHIFT) & SMC_SERVICE_CALL_MASK); |
| assert(service >= 0 && service <= 0xFFFF); |
| |
| if (service <= SMC_CALL_VENDOR_HYP_SERVICE) { |
| return service; |
| } else if (service < SMC_CALL_TRUSTED_APP) { |
| return SMC_CALL_RESERVED; |
| } else if (service < SMC_CALL_TRUSTED_OS) { |
| return SMC_CALL_TRUSTED_APP; |
| } else if (service < SMC_CALL_RESERVED) { |
| return SMC_CALL_TRUSTED_OS; |
| } else { |
| return SMC_CALL_RESERVED; |
| } |
| } |
| |
| static bool smc_call_is_32(uintptr_t func_id) |
| { |
| return !!(func_id & SMC_CALLING_CONVENTION) == SMC_CALLING_CONVENTION_32; |
| } |
| |
| static bool smc_call_is_atomic(uintptr_t func_id) |
| { |
| return !!(func_id & SMC_FAST_CALL); |
| } |
| |
| static uintptr_t smc_get_function_number(uintptr_t func_id) |
| { |
| return (func_id & SMC_FUNC_ID_MASK); |
| } |
| |
| int handle_smc(vm_vcpu_t *vcpu, uint32_t hsr) |
| { |
| int err; |
| seL4_UserContext regs; |
| err = vm_get_thread_context(vcpu, ®s); |
| if (err) { |
| ZF_LOGE("Failed to get vcpu registers to decode smc fault"); |
| return -1; |
| } |
| seL4_Word id = smc_get_function_id(®s); |
| seL4_Word fn_number = smc_get_function_number(id); |
| smc_call_id_t service = smc_get_call(id); |
| |
| switch (service) { |
| case SMC_CALL_ARM_ARCH: |
| ZF_LOGE("Unhandled SMC: arm architecture call %lu\n", fn_number); |
| break; |
| case SMC_CALL_CPU_SERVICE: |
| ZF_LOGE("Unhandled SMC: CPU service call %lu\n", fn_number); |
| break; |
| case SMC_CALL_SIP_SERVICE: |
| ZF_LOGE("Got SiP service call %lu\n", fn_number); |
| break; |
| case SMC_CALL_OEM_SERVICE: |
| ZF_LOGE("Unhandled SMC: OEM service call %lu\n", fn_number); |
| break; |
| case SMC_CALL_STD_SERVICE: |
| if (fn_number < PSCI_MAX) { |
| return handle_psci(vcpu, fn_number, smc_call_is_32(id)); |
| } |
| ZF_LOGE("Unhandled SMC: standard service call %lu\n", fn_number); |
| break; |
| case SMC_CALL_STD_HYP_SERVICE: |
| ZF_LOGE("Unhandled SMC: standard hyp service call %lu\n", fn_number); |
| break; |
| case SMC_CALL_VENDOR_HYP_SERVICE: |
| ZF_LOGE("Unhandled SMC: vendor hyp service call %lu\n", fn_number); |
| break; |
| case SMC_CALL_TRUSTED_APP: |
| ZF_LOGE("Unhandled SMC: trusted app call %lu\n", fn_number); |
| break; |
| case SMC_CALL_TRUSTED_OS: |
| ZF_LOGE("Unhandled SMC: trusted os call %lu\n", fn_number); |
| break; |
| default: |
| ZF_LOGE("Unhandle SMC: unknown value service: %lu fn_number: %lu\n", |
| (unsigned long) service, fn_number); |
| break; |
| } |
| return -1; |
| } |