Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: riscv: selftests: Add exception handling support

Add the infrastructure for guest exception handling in riscv selftests.
Customized handlers can be enabled by vm_install_exception_handler(vector)
or vm_install_interrupt_handler().

The code is inspired from that of x86/arm64.

Signed-off-by: Haibo Xu <haibo1.xu@intel.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Anup Patel <anup@brainfault.org>

authored by

Haibo Xu and committed by
Anup Patel
38f680c2 feb2c8fa

+221
+1
tools/testing/selftests/kvm/Makefile
··· 53 53 LIBKVM_s390x += lib/s390x/processor.c 54 54 LIBKVM_s390x += lib/s390x/ucall.c 55 55 56 + LIBKVM_riscv += lib/riscv/handlers.S 56 57 LIBKVM_riscv += lib/riscv/processor.c 57 58 LIBKVM_riscv += lib/riscv/ucall.c 58 59
+50
tools/testing/selftests/kvm/include/riscv/processor.h
··· 48 48 KVM_REG_RISCV_SBI_SINGLE, \ 49 49 idx, KVM_REG_SIZE_ULONG) 50 50 51 + struct ex_regs { 52 + unsigned long ra; 53 + unsigned long sp; 54 + unsigned long gp; 55 + unsigned long tp; 56 + unsigned long t0; 57 + unsigned long t1; 58 + unsigned long t2; 59 + unsigned long s0; 60 + unsigned long s1; 61 + unsigned long a0; 62 + unsigned long a1; 63 + unsigned long a2; 64 + unsigned long a3; 65 + unsigned long a4; 66 + unsigned long a5; 67 + unsigned long a6; 68 + unsigned long a7; 69 + unsigned long s2; 70 + unsigned long s3; 71 + unsigned long s4; 72 + unsigned long s5; 73 + unsigned long s6; 74 + unsigned long s7; 75 + unsigned long s8; 76 + unsigned long s9; 77 + unsigned long s10; 78 + unsigned long s11; 79 + unsigned long t3; 80 + unsigned long t4; 81 + unsigned long t5; 82 + unsigned long t6; 83 + unsigned long epc; 84 + unsigned long status; 85 + unsigned long cause; 86 + }; 87 + 88 + #define NR_VECTORS 2 89 + #define NR_EXCEPTIONS 32 90 + #define EC_MASK (NR_EXCEPTIONS - 1) 91 + 92 + typedef void(*exception_handler_fn)(struct ex_regs *); 93 + 94 + void vm_init_vector_tables(struct kvm_vm *vm); 95 + void vcpu_init_vector_tables(struct kvm_vcpu *vcpu); 96 + 97 + void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handler_fn handler); 98 + 99 + void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler); 100 + 51 101 /* L3 index Bit[47:39] */ 52 102 #define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL 53 103 #define PGTBL_L3_INDEX_SHIFT 39
+101
tools/testing/selftests/kvm/lib/riscv/handlers.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2023 Intel Corporation 4 + */ 5 + 6 + #ifndef __ASSEMBLY__ 7 + #define __ASSEMBLY__ 8 + #endif 9 + 10 + #include <asm/csr.h> 11 + 12 + .macro save_context 13 + addi sp, sp, (-8*34) 14 + sd x1, 0(sp) 15 + sd x2, 8(sp) 16 + sd x3, 16(sp) 17 + sd x4, 24(sp) 18 + sd x5, 32(sp) 19 + sd x6, 40(sp) 20 + sd x7, 48(sp) 21 + sd x8, 56(sp) 22 + sd x9, 64(sp) 23 + sd x10, 72(sp) 24 + sd x11, 80(sp) 25 + sd x12, 88(sp) 26 + sd x13, 96(sp) 27 + sd x14, 104(sp) 28 + sd x15, 112(sp) 29 + sd x16, 120(sp) 30 + sd x17, 128(sp) 31 + sd x18, 136(sp) 32 + sd x19, 144(sp) 33 + sd x20, 152(sp) 34 + sd x21, 160(sp) 35 + sd x22, 168(sp) 36 + sd x23, 176(sp) 37 + sd x24, 184(sp) 38 + sd x25, 192(sp) 39 + sd x26, 200(sp) 40 + sd x27, 208(sp) 41 + sd x28, 216(sp) 42 + sd x29, 224(sp) 43 + sd x30, 232(sp) 44 + sd x31, 240(sp) 45 + csrr s0, CSR_SEPC 46 + csrr s1, CSR_SSTATUS 47 + csrr s2, CSR_SCAUSE 48 + sd s0, 248(sp) 49 + sd s1, 256(sp) 50 + sd s2, 264(sp) 51 + .endm 52 + 53 + .macro restore_context 54 + ld s2, 264(sp) 55 + ld s1, 256(sp) 56 + ld s0, 248(sp) 57 + csrw CSR_SCAUSE, s2 58 + csrw CSR_SSTATUS, s1 59 + csrw CSR_SEPC, s0 60 + ld x31, 240(sp) 61 + ld x30, 232(sp) 62 + ld x29, 224(sp) 63 + ld x28, 216(sp) 64 + ld x27, 208(sp) 65 + ld x26, 200(sp) 66 + ld x25, 192(sp) 67 + ld x24, 184(sp) 68 + ld x23, 176(sp) 69 + ld x22, 168(sp) 70 + ld x21, 160(sp) 71 + ld x20, 152(sp) 72 + ld x19, 144(sp) 73 + ld x18, 136(sp) 74 + ld x17, 128(sp) 75 + ld x16, 120(sp) 76 + ld x15, 112(sp) 77 + ld x14, 104(sp) 78 + ld x13, 96(sp) 79 + ld x12, 88(sp) 80 + ld x11, 80(sp) 81 + ld x10, 72(sp) 82 + ld x9, 64(sp) 83 + ld x8, 56(sp) 84 + ld x7, 48(sp) 85 + ld x6, 40(sp) 86 + ld x5, 32(sp) 87 + ld x4, 24(sp) 88 + ld x3, 16(sp) 89 + ld x2, 8(sp) 90 + ld x1, 0(sp) 91 + addi sp, sp, (8*34) 92 + .endm 93 + 94 + .balign 4 95 + .global exception_vectors 96 + exception_vectors: 97 + save_context 98 + move a0, sp 99 + call route_exception 100 + restore_context 101 + sret
+69
tools/testing/selftests/kvm/lib/riscv/processor.c
··· 13 13 14 14 #define DEFAULT_RISCV_GUEST_STACK_VADDR_MIN 0xac0000 15 15 16 + static vm_vaddr_t exception_handlers; 17 + 16 18 static uint64_t page_align(struct kvm_vm *vm, uint64_t v) 17 19 { 18 20 return (v + vm->page_size) & ~(vm->page_size - 1); ··· 366 364 va_end(ap); 367 365 } 368 366 367 + void kvm_exit_unexpected_exception(int vector, int ec) 368 + { 369 + ucall(UCALL_UNHANDLED, 2, vector, ec); 370 + } 371 + 369 372 void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) 370 373 { 374 + struct ucall uc; 375 + 376 + if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) { 377 + TEST_FAIL("Unexpected exception (vector:0x%lx, ec:0x%lx)", 378 + uc.args[0], uc.args[1]); 379 + } 380 + } 381 + 382 + struct handlers { 383 + exception_handler_fn exception_handlers[NR_VECTORS][NR_EXCEPTIONS]; 384 + }; 385 + 386 + void route_exception(struct ex_regs *regs) 387 + { 388 + struct handlers *handlers = (struct handlers *)exception_handlers; 389 + int vector = 0, ec; 390 + 391 + ec = regs->cause & ~CAUSE_IRQ_FLAG; 392 + if (ec >= NR_EXCEPTIONS) 393 + goto unexpected_exception; 394 + 395 + /* Use the same handler for all the interrupts */ 396 + if (regs->cause & CAUSE_IRQ_FLAG) { 397 + vector = 1; 398 + ec = 0; 399 + } 400 + 401 + if (handlers && handlers->exception_handlers[vector][ec]) 402 + return handlers->exception_handlers[vector][ec](regs); 403 + 404 + unexpected_exception: 405 + return kvm_exit_unexpected_exception(vector, ec); 406 + } 407 + 408 + void vcpu_init_vector_tables(struct kvm_vcpu *vcpu) 409 + { 410 + extern char exception_vectors; 411 + 412 + vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(stvec), (unsigned long)&exception_vectors); 413 + } 414 + 415 + void vm_init_vector_tables(struct kvm_vm *vm) 416 + { 417 + vm->handlers = __vm_vaddr_alloc(vm, sizeof(struct handlers), 418 + vm->page_size, MEM_REGION_DATA); 419 + 420 + *(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers; 421 + } 422 + 423 + void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handler_fn handler) 424 + { 425 + struct handlers *handlers = addr_gva2hva(vm, vm->handlers); 426 + 427 + assert(vector < NR_EXCEPTIONS); 428 + handlers->exception_handlers[0][vector] = handler; 429 + } 430 + 431 + void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler) 432 + { 433 + struct handlers *handlers = addr_gva2hva(vm, vm->handlers); 434 + 435 + handlers->exception_handlers[1][0] = handler; 371 436 } 372 437 373 438 struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,