Hi Ricardo, On 5/12/21 9:27 AM, Ricardo Koller wrote: > On Fri, May 07, 2021 at 04:08:07PM +0200, Auger Eric wrote: >> Hi Ricardo, >> >> On 5/6/21 9:14 PM, Ricardo Koller wrote: >>> On Thu, May 06, 2021 at 02:30:17PM +0200, Auger Eric wrote: >>>> Hi Ricardo, >>>> >>> >>> Hi Eric, >>> >>> Thank you very much for the test. >>> >>>> On 5/3/21 9:12 PM, Ricardo Koller wrote: >>>>> On Mon, May 03, 2021 at 11:32:39AM +0100, Marc Zyngier wrote: >>>>>> On Sat, 01 May 2021 00:24:06 +0100, >>>>>> Ricardo Koller <ricarkol@xxxxxxxxxx> wrote: >>>>>>> >>>>>>> Add the infrastructure needed to enable exception handling in aarch64 >>>>>>> selftests. The exception handling defaults to an unhandled-exception >>>>>>> handler which aborts the test, just like x86. These handlers can be >>>>>>> overridden by calling vm_install_vector_handler(vector) or >>>>>>> vm_install_exception_handler(vector, ec). The unhandled exception >>>>>>> reporting from the guest is done using the ucall type introduced in a >>>>>>> previous commit, UCALL_UNHANDLED. >>>>>>> >>>>>>> The exception handling code is heavily inspired on kvm-unit-tests. >>>> >>>> running the test on 5.12 I get >>>> > > Hi Eric, > > I'm able to reproduce the failure you are seeing on 5.6, specifically > with kernels older than this commit: > > 4942dc6638b0 KVM: arm64: Write arch.mdcr_el2 changes since last vcpu_load on VHE > > but not yet on v5.12. Could you share the commit of the kernel you are > testing, please? my host is a 5.12 kernel (8404c9fbc84b) Thanks Eric > > Thanks! > Ricardo > >>>> ==== Test Assertion Failure ==== >>>> aarch64/debug-exceptions.c:232: false >>>> pid=6477 tid=6477 errno=4 - Interrupted system call >>>> 1 0x000000000040147b: main at debug-exceptions.c:230 >>>> 2 0x000003ff8aa60de3: ?? ??:0 >>>> 3 0x0000000000401517: _start at :? >>>> Failed guest assert: hw_bp_addr == PC(hw_bp) at >>>> aarch64/debug-exceptions.c:105 >>>> values: 0, 0x401794 >>>> >>>> >>>> I guess it is not an expected result. Any known bug waiting on the list? >>>> >>> >>> Not expected. That should work, or at least abort early because there is >>> no HW breakpoints support. >>> >>> I'm trying to reproduce the failure; can you help me with some >>> questions, please? >> sure, please find the answers below. >>> >>> - does your setup have support for hardware breakpoints? Can you try a >>> 'dmesg | grep break'? I'm looking for something like 'hw-breakpoint: >>> found ...'. If there is no such line it's very likely that the check >>> for "debug_ver >= 6" is not enough and the test should check for >>> "num_breakpoints > 0". >> [ 25.640418] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers. >>> - does it fail consistently (every single attempt)? >> yes it does. >> >> I will try to find some time to investigate too >> >> Thanks >> >> Eric >>> >>> Thanks! >>> Ricardo >>> >>>> >>>> Thanks >>>> >>>> Eric >>> >>> >>>>>>> >>>>>>> Signed-off-by: Ricardo Koller <ricarkol@xxxxxxxxxx> >>>>>>> --- >>>>>>> tools/testing/selftests/kvm/Makefile | 2 +- >>>>>>> .../selftests/kvm/include/aarch64/processor.h | 78 +++++++++++ >>>>>>> .../selftests/kvm/lib/aarch64/handlers.S | 130 ++++++++++++++++++ >>>>>>> .../selftests/kvm/lib/aarch64/processor.c | 124 +++++++++++++++++ >>>>>>> 4 files changed, 333 insertions(+), 1 deletion(-) >>>>>>> create mode 100644 tools/testing/selftests/kvm/lib/aarch64/handlers.S >>>>>>> >>>>>>> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile >>>>>>> index 4e548d7ab0ab..618c5903f478 100644 >>>>>>> --- a/tools/testing/selftests/kvm/Makefile >>>>>>> +++ b/tools/testing/selftests/kvm/Makefile >>>>>>> @@ -35,7 +35,7 @@ endif >>>>>>> >>>>>>> LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c lib/test_util.c lib/guest_modes.c lib/perf_test_util.c >>>>>>> LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/svm.c lib/x86_64/ucall.c lib/x86_64/handlers.S >>>>>>> -LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c >>>>>>> +LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c lib/aarch64/handlers.S >>>>>>> LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c >>>>>>> >>>>>>> TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test >>>>>>> diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h >>>>>>> index b7fa0c8551db..40aae31b4afc 100644 >>>>>>> --- a/tools/testing/selftests/kvm/include/aarch64/processor.h >>>>>>> +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h >>>>>>> @@ -8,6 +8,7 @@ >>>>>>> #define SELFTEST_KVM_PROCESSOR_H >>>>>>> >>>>>>> #include "kvm_util.h" >>>>>>> +#include <linux/stringify.h> >>>>>>> >>>>>>> >>>>>>> #define ARM64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ >>>>>>> @@ -18,6 +19,7 @@ >>>>>>> #define MAIR_EL1 3, 0, 10, 2, 0 >>>>>>> #define TTBR0_EL1 3, 0, 2, 0, 0 >>>>>>> #define SCTLR_EL1 3, 0, 1, 0, 0 >>>>>>> +#define VBAR_EL1 3, 0, 12, 0, 0 >>>>>>> >>>>>>> /* >>>>>>> * Default MAIR >>>>>>> @@ -56,4 +58,80 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, int vcpuid, struct kvm_vcpu_init *ini >>>>>>> void aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, >>>>>>> struct kvm_vcpu_init *init, void *guest_code); >>>>>>> >>>>>>> +struct ex_regs { >>>>>>> + u64 regs[31]; >>>>>>> + u64 sp; >>>>>>> + u64 pc; >>>>>>> + u64 pstate; >>>>>>> +}; >>>>>>> + >>>>>>> +#define VECTOR_NUM 16 >>>>>>> + >>>>>>> +enum { >>>>>>> + VECTOR_SYNC_CURRENT_SP0, >>>>>>> + VECTOR_IRQ_CURRENT_SP0, >>>>>>> + VECTOR_FIQ_CURRENT_SP0, >>>>>>> + VECTOR_ERROR_CURRENT_SP0, >>>>>>> + >>>>>>> + VECTOR_SYNC_CURRENT, >>>>>>> + VECTOR_IRQ_CURRENT, >>>>>>> + VECTOR_FIQ_CURRENT, >>>>>>> + VECTOR_ERROR_CURRENT, >>>>>>> + >>>>>>> + VECTOR_SYNC_LOWER_64, >>>>>>> + VECTOR_IRQ_LOWER_64, >>>>>>> + VECTOR_FIQ_LOWER_64, >>>>>>> + VECTOR_ERROR_LOWER_64, >>>>>>> + >>>>>>> + VECTOR_SYNC_LOWER_32, >>>>>>> + VECTOR_IRQ_LOWER_32, >>>>>>> + VECTOR_FIQ_LOWER_32, >>>>>>> + VECTOR_ERROR_LOWER_32, >>>>>>> +}; >>>>>>> + >>>>>>> +#define VECTOR_IS_SYNC(v) ((v) == VECTOR_SYNC_CURRENT_SP0 || \ >>>>>>> + (v) == VECTOR_SYNC_CURRENT || \ >>>>>>> + (v) == VECTOR_SYNC_LOWER_64 || \ >>>>>>> + (v) == VECTOR_SYNC_LOWER_32) >>>>>>> + >>>>>>> +/* Some common EC (Exception classes) */ >>>>>>> +#define ESR_EC_ILLEGAL_INS 0x0e >>>>>>> +#define ESR_EC_SVC64 0x15 >>>>>>> +#define ESR_EC_IABORT_CURRENT 0x21 >>>>>>> +#define ESR_EC_DABORT_CURRENT 0x25 >>>>>>> +#define ESR_EC_SERROR 0x2f >>>>>>> +#define ESR_EC_HW_BP_CURRENT 0x31 >>>>>>> +#define ESR_EC_SSTEP_CURRENT 0x33 >>>>>>> +#define ESR_EC_WP_CURRENT 0x35 >>>>>>> +#define ESR_EC_BRK_INS 0x3C >>>>>>> + >>>>>>> +#define ESR_EC_NUM 64 >>>>>>> + >>>>>>> +#define ESR_EC_SHIFT 26 >>>>>>> +#define ESR_EC_MASK (ESR_EC_NUM - 1) >>>>>>> + >>>>>>> +void vm_init_descriptor_tables(struct kvm_vm *vm); >>>>>>> +void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid); >>>>>>> + >>>>>>> +typedef void(*handler_fn)(struct ex_regs *); >>>>>>> +void vm_install_exception_handler(struct kvm_vm *vm, >>>>>>> + int vector, int ec, handler_fn handler); >>>>>>> +void vm_install_vector_handler(struct kvm_vm *vm, >>>>>>> + int vector, handler_fn handler); >>>>>>> + >>>>>>> +#define SPSR_D (1 << 9) >>>>>>> +#define SPSR_SS (1 << 21) >>>>>>> + >>>>>>> +#define write_sysreg(reg, val) \ >>>>>>> +({ \ >>>>>>> + u64 __val = (u64)(val); \ >>>>>>> + asm volatile("msr " __stringify(reg) ", %x0" : : "rZ" (__val)); \ >>>>>>> +}) >>>>>>> + >>>>>>> +#define read_sysreg(reg) \ >>>>>>> +({ u64 val; \ >>>>>>> + asm volatile("mrs %0, "__stringify(reg) : "=r"(val) : : "memory");\ >>>>>>> + val; \ >>>>>>> +}) >>>>>>> + >>>>>>> #endif /* SELFTEST_KVM_PROCESSOR_H */ >>>>>>> diff --git a/tools/testing/selftests/kvm/lib/aarch64/handlers.S b/tools/testing/selftests/kvm/lib/aarch64/handlers.S >>>>>>> new file mode 100644 >>>>>>> index 000000000000..8a560021892b >>>>>>> --- /dev/null >>>>>>> +++ b/tools/testing/selftests/kvm/lib/aarch64/handlers.S >>>>>>> @@ -0,0 +1,130 @@ >>>>>>> +/* SPDX-License-Identifier: GPL-2.0 */ >>>>>>> +.macro save_registers, vector >>>>>>> + add sp, sp, #-16 * 17 >>>>>>> + >>>>>>> + stp x0, x1, [sp, #16 * 0] >>>>>>> + stp x2, x3, [sp, #16 * 1] >>>>>>> + stp x4, x5, [sp, #16 * 2] >>>>>>> + stp x6, x7, [sp, #16 * 3] >>>>>>> + stp x8, x9, [sp, #16 * 4] >>>>>>> + stp x10, x11, [sp, #16 * 5] >>>>>>> + stp x12, x13, [sp, #16 * 6] >>>>>>> + stp x14, x15, [sp, #16 * 7] >>>>>>> + stp x16, x17, [sp, #16 * 8] >>>>>>> + stp x18, x19, [sp, #16 * 9] >>>>>>> + stp x20, x21, [sp, #16 * 10] >>>>>>> + stp x22, x23, [sp, #16 * 11] >>>>>>> + stp x24, x25, [sp, #16 * 12] >>>>>>> + stp x26, x27, [sp, #16 * 13] >>>>>>> + stp x28, x29, [sp, #16 * 14] >>>>>>> + >>>>>>> + .if \vector >= 8 >>>>>>> + mrs x1, sp_el0 >>>>>> >>>>>> I'm still a bit perplexed by this. SP_EL0 is never changed, since you >>>>>> always run in handler mode. Therefore, saving/restoring it is only >>>>>> overhead. If an exception handler wants to introspect it, it is >>>>>> already available in the relevant system register. >>>>>> >>>>>> Or did you have something else in mind for it? >>>>>> >>>>> >>>>> Not really. The reason for saving sp_el0 in there was just for >>>>> consistency, so that handlers for both el0 and el1 exceptions could get >>>>> the sp at regs->sp. >>>>> >>>>> Restoring sp_el0 might be too much. So, what do you think of this v3: we >>>>> keep the saving of sp_el0 into regs->sp (to keep things the same between >>>>> el0 and el1) and delete the restoring of sp_el0? >>>>> >>>>> Thanks, >>>>> Ricardo >>>>> >>>>>>> + .else >>>>>>> + /* >>>>>>> + * This stores sp_el1 into ex_regs.sp so exception handlers can >>>>>>> + * "look" at it. It will _not_ be used to restore the sp_el1 on >>>>>>> + * return from the exception so handlers can not update it. >>>>>>> + */ >>>>>>> + mov x1, sp >>>>>>> + .endif >>>>>>> + stp x30, x1, [sp, #16 * 15] /* x30, SP */ >>>>>>> + >>>>>>> + mrs x1, elr_el1 >>>>>>> + mrs x2, spsr_el1 >>>>>>> + stp x1, x2, [sp, #16 * 16] /* PC, PSTATE */ >>>>>>> +.endm >>>>>>> + >>>>>>> +.macro restore_registers, vector >>>>>>> + ldp x1, x2, [sp, #16 * 16] /* PC, PSTATE */ >>>>>>> + msr elr_el1, x1 >>>>>>> + msr spsr_el1, x2 >>>>>>> + >>>>>>> + ldp x30, x1, [sp, #16 * 15] /* x30, SP */ >>>>>>> + .if \vector >= 8 >>>>>>> + msr sp_el0, x1 >>>>>>> + .endif >>>>>>> + >>>>>>> + ldp x28, x29, [sp, #16 * 14] >>>>>>> + ldp x26, x27, [sp, #16 * 13] >>>>>>> + ldp x24, x25, [sp, #16 * 12] >>>>>>> + ldp x22, x23, [sp, #16 * 11] >>>>>>> + ldp x20, x21, [sp, #16 * 10] >>>>>>> + ldp x18, x19, [sp, #16 * 9] >>>>>>> + ldp x16, x17, [sp, #16 * 8] >>>>>>> + ldp x14, x15, [sp, #16 * 7] >>>>>>> + ldp x12, x13, [sp, #16 * 6] >>>>>>> + ldp x10, x11, [sp, #16 * 5] >>>>>>> + ldp x8, x9, [sp, #16 * 4] >>>>>>> + ldp x6, x7, [sp, #16 * 3] >>>>>>> + ldp x4, x5, [sp, #16 * 2] >>>>>>> + ldp x2, x3, [sp, #16 * 1] >>>>>>> + ldp x0, x1, [sp, #16 * 0] >>>>>>> + >>>>>>> + add sp, sp, #16 * 17 >>>>>>> + >>>>>>> + eret >>>>>>> +.endm >>>>>>> + >>>>>>> +.pushsection ".entry.text", "ax" >>>>>>> +.balign 0x800 >>>>>>> +.global vectors >>>>>>> +vectors: >>>>>>> +.popsection >>>>>>> + >>>>>>> +.set vector, 0 >>>>>>> + >>>>>>> +/* >>>>>>> + * Build an exception handler for vector and append a jump to it into >>>>>>> + * vectors (while making sure that it's 0x80 aligned). >>>>>>> + */ >>>>>>> +.macro HANDLER, label >>>>>>> +handler_\()\label: >>>>>>> + save_registers vector >>>>>>> + mov x0, sp >>>>>>> + mov x1, #vector >>>>>>> + bl route_exception >>>>>>> + restore_registers vector >>>>>>> + >>>>>>> +.pushsection ".entry.text", "ax" >>>>>>> +.balign 0x80 >>>>>>> + b handler_\()\label >>>>>>> +.popsection >>>>>>> + >>>>>>> +.set vector, vector + 1 >>>>>>> +.endm >>>>>>> + >>>>>>> +.macro HANDLER_INVALID >>>>>>> +.pushsection ".entry.text", "ax" >>>>>>> +.balign 0x80 >>>>>>> +/* This will abort so no need to save and restore registers. */ >>>>>>> + mov x0, #vector >>>>>>> + b kvm_exit_unexpected_vector >>>>>>> +.popsection >>>>>>> + >>>>>>> +.set vector, vector + 1 >>>>>>> +.endm >>>>>>> + >>>>>>> +/* >>>>>>> + * Caution: be sure to not add anything between the declaration of vectors >>>>>>> + * above and these macro calls that will build the vectors table below it. >>>>>>> + */ >>>>>>> + HANDLER_INVALID // Synchronous EL1t >>>>>>> + HANDLER_INVALID // IRQ EL1t >>>>>>> + HANDLER_INVALID // FIQ EL1t >>>>>>> + HANDLER_INVALID // Error EL1t >>>>>>> + >>>>>>> + HANDLER el1h_sync // Synchronous EL1h >>>>>>> + HANDLER el1h_irq // IRQ EL1h >>>>>>> + HANDLER el1h_fiq // FIQ EL1h >>>>>>> + HANDLER el1h_error // Error EL1h >>>>>>> + >>>>>>> + HANDLER el0_sync_64 // Synchronous 64-bit EL0 >>>>>>> + HANDLER el0_irq_64 // IRQ 64-bit EL0 >>>>>>> + HANDLER el0_fiq_64 // FIQ 64-bit EL0 >>>>>>> + HANDLER el0_error_64 // Error 64-bit EL0 >>>>>>> + >>>>>>> + HANDLER el0_sync_32 // Synchronous 32-bit EL0 >>>>>>> + HANDLER el0_irq_32 // IRQ 32-bit EL0 >>>>>>> + HANDLER el0_fiq_32 // FIQ 32-bit EL0 >>>>>>> + HANDLER el0_error_32 // Error 32-bit EL0 >>>>>>> diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c >>>>>>> index cee92d477dc0..25be71ec88be 100644 >>>>>>> --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c >>>>>>> +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c >>>>>>> @@ -6,6 +6,7 @@ >>>>>>> */ >>>>>>> >>>>>>> #include <linux/compiler.h> >>>>>>> +#include <assert.h> >>>>>>> >>>>>>> #include "kvm_util.h" >>>>>>> #include "../kvm_util_internal.h" >>>>>>> @@ -14,6 +15,8 @@ >>>>>>> #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 >>>>>>> #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN 0xac0000 >>>>>>> >>>>>>> +vm_vaddr_t exception_handlers; >>>>>>> + >>>>>>> static uint64_t page_align(struct kvm_vm *vm, uint64_t v) >>>>>>> { >>>>>>> return (v + vm->page_size) & ~(vm->page_size - 1); >>>>>>> @@ -334,6 +337,127 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) >>>>>>> va_end(ap); >>>>>>> } >>>>>>> >>>>>>> +void kvm_exit_unexpected_vector(int vector) >>>>>>> +{ >>>>>>> + ucall(UCALL_UNHANDLED, 3, vector, 0, false /* !valid_ec */); >>>>>>> +} >>>>>>> + >>>>>>> +void kvm_exit_unexpected_exception(int vector, uint64_t ec) >>>>>>> +{ >>>>>>> + ucall(UCALL_UNHANDLED, 3, vector, ec, true /* valid_ec */); >>>>>>> +} >>>>>>> + >>>>>>> void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid) >>>>>>> { >>>>>>> + struct ucall uc; >>>>>>> + >>>>>>> + if (get_ucall(vm, vcpuid, &uc) != UCALL_UNHANDLED) >>>>>>> + return; >>>>>>> + >>>>>>> + if (uc.args[2]) /* valid_ec */ { >>>>>>> + assert(VECTOR_IS_SYNC(uc.args[0])); >>>>>>> + TEST_ASSERT(false, >>>>>>> + "Unexpected exception (vector:0x%lx, ec:0x%lx)", >>>>>>> + uc.args[0], uc.args[1]); >>>>>>> + } else { >>>>>>> + assert(!VECTOR_IS_SYNC(uc.args[0])); >>>>>>> + TEST_ASSERT(false, >>>>>>> + "Unexpected exception (vector:0x%lx)", >>>>>>> + uc.args[0]); >>>>>>> + } >>>>>>> +} >>>>>>> + >>>>>>> +/* >>>>>>> + * This exception handling code was heavily inspired on kvm-unit-tests. There >>>>>>> + * is a set of default vector handlers stored in vector_handlers. These default >>>>>>> + * vector handlers call user-installed handlers stored in exception_handlers. >>>>>>> + * Synchronous handlers are indexed by (vector, ec), and irq handlers by >>>>>>> + * (vector, ec=0). >>>>>>> + */ >>>>>>> + >>>>>>> +typedef void(*vector_fn)(struct ex_regs *, int vector); >>>>>>> + >>>>>>> +struct handlers { >>>>>>> + vector_fn vector_handlers[VECTOR_NUM]; >>>>>>> + handler_fn exception_handlers[VECTOR_NUM][ESR_EC_NUM]; >>>>>>> +}; >>>>>>> + >>>>>>> +void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid) >>>>>>> +{ >>>>>>> + extern char vectors; >>>>>>> + >>>>>>> + set_reg(vm, vcpuid, ARM64_SYS_REG(VBAR_EL1), (uint64_t)&vectors); >>>>>>> +} >>>>>>> + >>>>>>> +void default_sync_handler(struct ex_regs *regs, int vector) >>>>>>> +{ >>>>>>> + struct handlers *handlers = (struct handlers *)exception_handlers; >>>>>>> + uint64_t esr = read_sysreg(esr_el1); >>>>>>> + uint64_t ec = (esr >> ESR_EC_SHIFT) & ESR_EC_MASK; >>>>>>> + >>>>>>> + GUEST_ASSERT(VECTOR_IS_SYNC(vector)); >>>>>>> + >>>>>>> + if (handlers && handlers->exception_handlers[vector][ec]) >>>>>>> + handlers->exception_handlers[vector][ec](regs); >>>>>>> + else >>>>>>> + kvm_exit_unexpected_exception(vector, ec); >>>>>>> +} >>>>>>> + >>>>>>> +void default_irq_handler(struct ex_regs *regs, int vector) >>>>>>> +{ >>>>>>> + struct handlers *handlers = (struct handlers *)exception_handlers; >>>>>>> + >>>>>>> + GUEST_ASSERT(!VECTOR_IS_SYNC(vector)); >>>>>>> + >>>>>>> + if (handlers && handlers->exception_handlers[vector][0]) >>>>>>> + handlers->exception_handlers[vector][0](regs); >>>>>>> + else >>>>>>> + kvm_exit_unexpected_vector(vector); >>>>>>> +} >>>>>>> + >>>>>>> +void route_exception(struct ex_regs *regs, int vector) >>>>>>> +{ >>>>>>> + struct handlers *handlers = (struct handlers *)exception_handlers; >>>>>>> + >>>>>>> + if (handlers && handlers->vector_handlers[vector]) >>>>>>> + handlers->vector_handlers[vector](regs, vector); >>>>>>> + else >>>>>>> + kvm_exit_unexpected_vector(vector); >>>>>>> +} >>>>>>> + >>>>>>> +void vm_init_descriptor_tables(struct kvm_vm *vm) >>>>>>> +{ >>>>>>> + struct handlers *handlers; >>>>>>> + >>>>>>> + vm->handlers = vm_vaddr_alloc(vm, sizeof(struct handlers), >>>>>>> + vm->page_size, 0, 0); >>>>>>> + >>>>>>> + handlers = (struct handlers *)addr_gva2hva(vm, vm->handlers); >>>>>>> + handlers->vector_handlers[VECTOR_SYNC_CURRENT] = default_sync_handler; >>>>>>> + handlers->vector_handlers[VECTOR_IRQ_CURRENT] = default_irq_handler; >>>>>>> + handlers->vector_handlers[VECTOR_SYNC_LOWER_64] = default_sync_handler; >>>>>>> + handlers->vector_handlers[VECTOR_IRQ_LOWER_64] = default_irq_handler; >>>>>> >>>>>> How about FIQ, Error? Although they are unlikely, they are valid >>>>>> exceptions. >>>>>> >>>>>>> + >>>>>>> + *(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers; >>>>>>> +} >>>>>>> + >>>>>>> +void vm_install_exception_handler(struct kvm_vm *vm, int vector, int ec, >>>>>>> + void (*handler)(struct ex_regs *)) >>>>>>> +{ >>>>>>> + struct handlers *handlers = (struct handlers *)addr_gva2hva(vm, vm->handlers); >>>>>>> + >>>>>>> + assert(VECTOR_IS_SYNC(vector)); >>>>>>> + assert(vector < VECTOR_NUM); >>>>>>> + assert(ec < ESR_EC_NUM); >>>>>>> + handlers->exception_handlers[vector][ec] = handler; >>>>>>> +} >>>>>>> + >>>>>>> +void vm_install_vector_handler(struct kvm_vm *vm, int vector, >>>>>>> + void (*handler)(struct ex_regs *)) >>>>>>> +{ >>>>>>> + struct handlers *handlers = (struct handlers *)addr_gva2hva(vm, vm->handlers); >>>>>>> + >>>>>>> + assert(!VECTOR_IS_SYNC(vector)); >>>>>>> + assert(vector < VECTOR_NUM); >>>>>>> + handlers->exception_handlers[vector][0] = handler; >>>>>>> } >>>>>> >>>>>> Thanks, >>>>>> >>>>>> M. >>>>>> >>>>>> -- >>>>>> Without deviation from the norm, progress is not possible. >>>>> >>>> >>> >> >