]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: LoongArch: selftests: Add exception handler register interface
authorBibo Mao <maobibo@loongson.cn>
Thu, 27 Nov 2025 03:00:18 +0000 (11:00 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Thu, 27 Nov 2025 03:00:18 +0000 (11:00 +0800)
Add interrupt and exception handler register interface. When exception
happens, execute registered exception handler if exists, else report an
error.

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
tools/testing/selftests/kvm/include/loongarch/processor.h
tools/testing/selftests/kvm/lib/loongarch/processor.c

index f1bfc06a22643806a0c085bddfd7cdfabcb162d1..a1930f28e0448d7310d99d97216145ed2fa3c4ae 100644 (file)
 #define LOONGARCH_CSR_EUEN             0x2
 #define LOONGARCH_CSR_ECFG             0x4
 #define LOONGARCH_CSR_ESTAT            0x5  /* Exception status */
+#define  CSR_ESTAT_EXC_SHIFT           16
+#define  CSR_ESTAT_EXC_WIDTH           6
+#define  CSR_ESTAT_EXC                 (0x3f << CSR_ESTAT_EXC_SHIFT)
+#define    EXCCODE_INT                 0    /* Interrupt */
+#define      INT_TI                    11   /* Timer interrupt*/
 #define LOONGARCH_CSR_ERA              0x6  /* ERA */
 #define LOONGARCH_CSR_BADV             0x7  /* Bad virtual address */
 #define LOONGARCH_CSR_EENTRY           0xc
@@ -155,6 +160,17 @@ struct ex_regs {
 #define PRMD_OFFSET_EXREGS             offsetof(struct ex_regs, prmd)
 #define EXREGS_SIZE                    sizeof(struct ex_regs)
 
+#define VECTOR_NUM                     64
+
+typedef void(*handler_fn)(struct ex_regs *);
+
+struct handlers {
+       handler_fn exception_handlers[VECTOR_NUM];
+};
+
+void vm_init_descriptor_tables(struct kvm_vm *vm);
+void vm_install_exception_handler(struct kvm_vm *vm, int vector, handler_fn handler);
+
 static inline void cpu_relax(void)
 {
        asm volatile("nop" ::: "memory");
index 08b4cef48e443e02e4f327cd89431353202f7786..b2a1fa7b18da19a8599779f6989db6c9bf39ed8f 100644 (file)
@@ -11,6 +11,7 @@
 #define LOONGARCH_GUEST_STACK_VADDR_MIN                0x200000
 
 static vm_paddr_t invalid_pgtable[4];
+static vm_vaddr_t exception_handlers;
 
 static uint64_t virt_pte_index(struct kvm_vm *vm, vm_vaddr_t gva, int level)
 {
@@ -183,7 +184,14 @@ void assert_on_unhandled_exception(struct kvm_vcpu *vcpu)
 
 void route_exception(struct ex_regs *regs)
 {
+       int vector;
        unsigned long pc, estat, badv;
+       struct handlers *handlers;
+
+       handlers = (struct handlers *)exception_handlers;
+       vector = (regs->estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT;
+       if (handlers && handlers->exception_handlers[vector])
+               return handlers->exception_handlers[vector](regs);
 
        pc = regs->pc;
        badv  = regs->badv;
@@ -192,6 +200,27 @@ void route_exception(struct ex_regs *regs)
        while (1) ;
 }
 
+void vm_init_descriptor_tables(struct kvm_vm *vm)
+{
+       void *addr;
+
+       vm->handlers = __vm_vaddr_alloc(vm, sizeof(struct handlers),
+                       LOONGARCH_GUEST_STACK_VADDR_MIN, MEM_REGION_DATA);
+
+       addr = addr_gva2hva(vm, vm->handlers);
+       memset(addr, 0, vm->page_size);
+       exception_handlers = vm->handlers;
+       sync_global_to_guest(vm, exception_handlers);
+}
+
+void vm_install_exception_handler(struct kvm_vm *vm, int vector, handler_fn handler)
+{
+       struct handlers *handlers = addr_gva2hva(vm, vm->handlers);
+
+       assert(vector < VECTOR_NUM);
+       handlers->exception_handlers[vector] = handler;
+}
+
 uint32_t guest_get_vcpuid(void)
 {
        return csr_read(LOONGARCH_CSR_CPUID);