diff --git a/src/arch/aarch64/fault.c b/src/arch/aarch64/fault.c index dca56d1d..871a2ed1 100644 --- a/src/arch/aarch64/fault.c +++ b/src/arch/aarch64/fault.c @@ -22,7 +22,8 @@ // return !CPSR_IS_THUMB(regs->spsr); // } -bool fault_advance_vcpu(size_t vcpu_id, seL4_UserContext *regs) { +bool fault_advance_vcpu(size_t vcpu_id, seL4_UserContext *regs) +{ // For now we just ignore it and continue // Assume 32-bit instruction regs->pc += 4; @@ -32,15 +33,23 @@ bool fault_advance_vcpu(size_t vcpu_id, seL4_UserContext *regs) { return (err == seL4_NoError); } -char *fault_to_string(seL4_Word fault_label) { +char *fault_to_string(seL4_Word fault_label) +{ switch (fault_label) { - case seL4_Fault_VMFault: return "virtual memory"; - case seL4_Fault_UnknownSyscall: return "unknown syscall"; - case seL4_Fault_UserException: return "user exception"; - case seL4_Fault_VGICMaintenance: return "VGIC maintenance"; - case seL4_Fault_VCPUFault: return "VCPU"; - case seL4_Fault_VPPIEvent: return "VPPI event"; - default: return "unknown fault"; + case seL4_Fault_VMFault: + return "virtual memory"; + case seL4_Fault_UnknownSyscall: + return "unknown syscall"; + case seL4_Fault_UserException: + return "user exception"; + case seL4_Fault_VGICMaintenance: + return "VGIC maintenance"; + case seL4_Fault_VCPUFault: + return "VCPU"; + case seL4_Fault_VPPIEvent: + return "VPPI event"; + default: + return "unknown fault"; } } @@ -59,7 +68,7 @@ enum fault_width { static enum fault_width fault_get_width(uint64_t fsr) { if (HSR_IS_SYNDROME_VALID(fsr) && HSR_SYNDROME_WIDTH(fsr) <= WIDTH_DOUBLEWORD) { - return (enum fault_width) (HSR_SYNDROME_WIDTH(fsr)); + return (enum fault_width)(HSR_SYNDROME_WIDTH(fsr)); } else { LOG_VMM_ERR("Received invalid FSR: 0x%lx\n", fsr); // @ivanv: reviist @@ -74,26 +83,26 @@ uint64_t fault_get_data_mask(uint64_t addr, uint64_t fsr) { uint64_t mask = 0; switch (fault_get_width(fsr)) { - case WIDTH_BYTE: - mask = 0x000000ff; - assert(!(addr & 0x0)); - break; - case WIDTH_HALFWORD: - mask = 0x0000ffff; - assert(!(addr & 0x1)); - break; - case WIDTH_WORD: - mask = 0xffffffff; - assert(!(addr & 0x3)); - break; - case WIDTH_DOUBLEWORD: - mask = ~mask; - break; - default: - LOG_VMM_ERR("unknown width: 0x%lx, from FSR: 0x%lx, addr: 0x%lx\n", - fault_get_width(fsr), fsr, addr); - assert(0); - return 0; + case WIDTH_BYTE: + mask = 0x000000ff; + assert(!(addr & 0x0)); + break; + case WIDTH_HALFWORD: + mask = 0x0000ffff; + assert(!(addr & 0x1)); + break; + case WIDTH_WORD: + mask = 0xffffffff; + assert(!(addr & 0x3)); + break; + case WIDTH_DOUBLEWORD: + mask = ~mask; + break; + default: + LOG_VMM_ERR("unknown width: 0x%lx, from FSR: 0x%lx, addr: 0x%lx\n", + fault_get_width(fsr), fsr, addr); + assert(0); + return 0; } mask <<= (addr & 0x3) * 8; return mask; @@ -108,41 +117,73 @@ seL4_Word *decode_rt(size_t reg_idx, seL4_UserContext *regs) * encodes the Syndrome Register transfer. */ switch (reg_idx) { - case 0: return ®s->x0; - case 1: return ®s->x1; - case 2: return ®s->x2; - case 3: return ®s->x3; - case 4: return ®s->x4; - case 5: return ®s->x5; - case 6: return ®s->x6; - case 7: return ®s->x7; - case 8: return ®s->x8; - case 9: return ®s->x9; - case 10: return ®s->x10; - case 11: return ®s->x11; - case 12: return ®s->x12; - case 13: return ®s->x13; - case 14: return ®s->x14; - case 15: return ®s->x15; - case 16: return ®s->x16; - case 17: return ®s->x17; - case 18: return ®s->x18; - case 19: return ®s->x19; - case 20: return ®s->x20; - case 21: return ®s->x21; - case 22: return ®s->x22; - case 23: return ®s->x23; - case 24: return ®s->x24; - case 25: return ®s->x25; - case 26: return ®s->x26; - case 27: return ®s->x27; - case 28: return ®s->x28; - case 29: return ®s->x29; - case 30: return ®s->x30; - case 31: return &wzr; - default: - LOG_VMM_ERR("failed to decode Rt, attempted to access invalid register index 0x%lx\n", reg_idx); - return NULL; + case 0: + return ®s->x0; + case 1: + return ®s->x1; + case 2: + return ®s->x2; + case 3: + return ®s->x3; + case 4: + return ®s->x4; + case 5: + return ®s->x5; + case 6: + return ®s->x6; + case 7: + return ®s->x7; + case 8: + return ®s->x8; + case 9: + return ®s->x9; + case 10: + return ®s->x10; + case 11: + return ®s->x11; + case 12: + return ®s->x12; + case 13: + return ®s->x13; + case 14: + return ®s->x14; + case 15: + return ®s->x15; + case 16: + return ®s->x16; + case 17: + return ®s->x17; + case 18: + return ®s->x18; + case 19: + return ®s->x19; + case 20: + return ®s->x20; + case 21: + return ®s->x21; + case 22: + return ®s->x22; + case 23: + return ®s->x23; + case 24: + return ®s->x24; + case 25: + return ®s->x25; + case 26: + return ®s->x26; + case 27: + return ®s->x27; + case 28: + return ®s->x28; + case 29: + return ®s->x29; + case 30: + return ®s->x30; + case 31: + return &wzr; + default: + LOG_VMM_ERR("failed to decode Rt, attempted to access invalid register index 0x%lx\n", reg_idx); + return NULL; } } @@ -195,7 +236,8 @@ uint64_t fault_emulate(seL4_UserContext *regs, uint64_t reg, uint64_t addr, uint } } -void fault_emulate_write(seL4_UserContext *regs, size_t addr, size_t fsr, size_t reg_val) { +void fault_emulate_write(seL4_UserContext *regs, size_t addr, size_t fsr, size_t reg_val) +{ // @ivanv: audit /* Get register opearand */ int rt = get_rt(fsr); @@ -219,14 +261,14 @@ bool fault_handle_vcpu_exception(size_t vcpu_id) uint32_t hsr = microkit_mr_get(seL4_VCPUFault_HSR); uint64_t hsr_ec_class = HSR_EXCEPTION_CLASS(hsr); switch (hsr_ec_class) { - case HSR_SMC_64_EXCEPTION: - 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; - default: - LOG_VMM_ERR("unknown SMC exception, EC class: 0x%lx, HSR: 0x%lx\n", hsr_ec_class, hsr); - return false; + case HSR_SMC_64_EXCEPTION: + 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; + default: + LOG_VMM_ERR("unknown SMC exception, EC class: 0x%lx, HSR: 0x%lx\n", hsr_ec_class, hsr); + return false; } } @@ -270,17 +312,17 @@ bool fault_handle_unknown_syscall(size_t vcpu_id) LOG_VMM("Received syscall 0x%lx\n", syscall); switch (syscall) { - case SYSCALL_PA_TO_IPA: - // @ivanv: why do we not do anything here? - // @ivanv, how to get the physical address to translate? - LOG_VMM("Received PA translation syscall\n"); - break; - case SYSCALL_NOP: - LOG_VMM("Received NOP syscall\n"); - break; - default: - LOG_VMM_ERR("Unknown syscall: syscall number: 0x%lx, PC: 0x%lx\n", syscall, fault_ip); - return false; + case SYSCALL_PA_TO_IPA: + // @ivanv: why do we not do anything here? + // @ivanv, how to get the physical address to translate? + LOG_VMM("Received PA translation syscall\n"); + break; + case SYSCALL_NOP: + LOG_VMM("Received NOP syscall\n"); + break; + default: + LOG_VMM_ERR("Unknown syscall: syscall number: 0x%lx, PC: 0x%lx\n", syscall, fault_ip); + return false; } seL4_UserContext regs; @@ -304,7 +346,8 @@ struct vm_exception_handler { struct vm_exception_handler registered_vm_exception_handlers[MAX_VM_EXCEPTION_HANDLERS]; size_t vm_exception_handler_index = 0; -bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_exception_handler_t callback, void *data) { +bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_exception_handler_t callback, void *data) +{ // @ivanv audit necessary here since this code was written very quickly. Other things to check such // as the region of memory is not overlapping with other regions, also should have GIC_DIST regions // use this API. @@ -328,7 +371,8 @@ bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_excepti return true; } -static bool fault_handle_registered_vm_exceptions(size_t vcpu_id, uintptr_t addr, size_t fsr, seL4_UserContext *regs) { +static bool fault_handle_registered_vm_exceptions(size_t vcpu_id, uintptr_t addr, size_t fsr, seL4_UserContext *regs) +{ for (int i = 0; i < MAX_VM_EXCEPTION_HANDLERS; i++) { uintptr_t base = registered_vm_exception_handlers[i].base; uintptr_t end = registered_vm_exception_handlers[i].end; @@ -338,7 +382,8 @@ static bool fault_handle_registered_vm_exceptions(size_t vcpu_id, uintptr_t addr bool success = callback(vcpu_id, addr - base, fsr, regs, data); if (!success) { // @ivanv: improve error message - LOG_VMM_ERR("registered virtual memory exception handler for region [0x%lx..0x%lx) at address 0x%lx failed\n", base, end, addr); + LOG_VMM_ERR("registered virtual memory exception handler for region [0x%lx..0x%lx) at address 0x%lx failed\n", base, + end, addr); } /* Whether or not the callback actually successfully handled the * exception, we return true to say that we at least found a handler @@ -372,7 +417,7 @@ bool fault_handle_vm_exception(size_t vcpu_id) size_t is_prefetch = seL4_GetMR(seL4_VMFault_PrefetchFault); bool is_write = fault_is_write(fsr); LOG_VMM_ERR("unexpected memory fault on address: 0x%lx, FSR: 0x%lx, IP: 0x%lx, is_prefetch: %s, is_write: %s\n", - addr, fsr, ip, is_prefetch ? "true" : "false", is_write ? "true" : "false"); + addr, fsr, ip, is_prefetch ? "true" : "false", is_write ? "true" : "false"); tcb_print_regs(vcpu_id); vcpu_print_regs(vcpu_id); } else { @@ -382,36 +427,37 @@ bool fault_handle_vm_exception(size_t vcpu_id) return success; } -bool fault_handle(size_t vcpu_id, microkit_msginfo msginfo) { +bool fault_handle(size_t vcpu_id, microkit_msginfo msginfo) +{ size_t label = microkit_msginfo_get_label(msginfo); bool success = false; switch (label) { - case seL4_Fault_VMFault: - success = fault_handle_vm_exception(vcpu_id); - break; - case seL4_Fault_UnknownSyscall: - success = fault_handle_unknown_syscall(vcpu_id); - break; - case seL4_Fault_UserException: - success = fault_handle_user_exception(vcpu_id); - break; - case seL4_Fault_VGICMaintenance: - success = fault_handle_vgic_maintenance(vcpu_id); - break; - case seL4_Fault_VCPUFault: - success = fault_handle_vcpu_exception(vcpu_id); - break; - case seL4_Fault_VPPIEvent: - success = fault_handle_vppi_event(vcpu_id); - break; - default: - /* We have reached a genuinely unexpected case, stop the guest. */ - LOG_VMM_ERR("unknown fault label 0x%lx, stopping guest with ID 0x%lx\n", label, vcpu_id); - microkit_vcpu_stop(vcpu_id); - /* Dump the TCB and vCPU registers to hopefully get information as - * to what has gone wrong. */ - tcb_print_regs(vcpu_id); - vcpu_print_regs(vcpu_id); + case seL4_Fault_VMFault: + success = fault_handle_vm_exception(vcpu_id); + break; + case seL4_Fault_UnknownSyscall: + success = fault_handle_unknown_syscall(vcpu_id); + break; + case seL4_Fault_UserException: + success = fault_handle_user_exception(vcpu_id); + break; + case seL4_Fault_VGICMaintenance: + success = fault_handle_vgic_maintenance(vcpu_id); + break; + case seL4_Fault_VCPUFault: + success = fault_handle_vcpu_exception(vcpu_id); + break; + case seL4_Fault_VPPIEvent: + success = fault_handle_vppi_event(vcpu_id); + break; + default: + /* We have reached a genuinely unexpected case, stop the guest. */ + LOG_VMM_ERR("unknown fault label 0x%lx, stopping guest with ID 0x%lx\n", label, vcpu_id); + microkit_vcpu_stop(vcpu_id); + /* Dump the TCB and vCPU registers to hopefully get information as + * to what has gone wrong. */ + tcb_print_regs(vcpu_id); + vcpu_print_regs(vcpu_id); } if (!success) {