Skip to content

Commit 38f680c

Browse files
xiaobo55xavpatel
authored andcommitted
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>
1 parent feb2c8f commit 38f680c

File tree

4 files changed

+221
-0
lines changed

4 files changed

+221
-0
lines changed

tools/testing/selftests/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ LIBKVM_s390x += lib/s390x/diag318_test_handler.c
5353
LIBKVM_s390x += lib/s390x/processor.c
5454
LIBKVM_s390x += lib/s390x/ucall.c
5555

56+
LIBKVM_riscv += lib/riscv/handlers.S
5657
LIBKVM_riscv += lib/riscv/processor.c
5758
LIBKVM_riscv += lib/riscv/ucall.c
5859

tools/testing/selftests/kvm/include/riscv/processor.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,56 @@ static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t subtype,
4848
KVM_REG_RISCV_SBI_SINGLE, \
4949
idx, KVM_REG_SIZE_ULONG)
5050

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+
51101
/* L3 index Bit[47:39] */
52102
#define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL
53103
#define PGTBL_L3_INDEX_SHIFT 39
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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

tools/testing/selftests/kvm/lib/riscv/processor.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
#define DEFAULT_RISCV_GUEST_STACK_VADDR_MIN 0xac0000
1515

16+
static vm_vaddr_t exception_handlers;
17+
1618
static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
1719
{
1820
return (v + vm->page_size) & ~(vm->page_size - 1);
@@ -364,8 +366,75 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
364366
va_end(ap);
365367
}
366368

369+
void kvm_exit_unexpected_exception(int vector, int ec)
370+
{
371+
ucall(UCALL_UNHANDLED, 2, vector, ec);
372+
}
373+
367374
void assert_on_unhandled_exception(struct kvm_vcpu *vcpu)
368375
{
376+
struct ucall uc;
377+
378+
if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) {
379+
TEST_FAIL("Unexpected exception (vector:0x%lx, ec:0x%lx)",
380+
uc.args[0], uc.args[1]);
381+
}
382+
}
383+
384+
struct handlers {
385+
exception_handler_fn exception_handlers[NR_VECTORS][NR_EXCEPTIONS];
386+
};
387+
388+
void route_exception(struct ex_regs *regs)
389+
{
390+
struct handlers *handlers = (struct handlers *)exception_handlers;
391+
int vector = 0, ec;
392+
393+
ec = regs->cause & ~CAUSE_IRQ_FLAG;
394+
if (ec >= NR_EXCEPTIONS)
395+
goto unexpected_exception;
396+
397+
/* Use the same handler for all the interrupts */
398+
if (regs->cause & CAUSE_IRQ_FLAG) {
399+
vector = 1;
400+
ec = 0;
401+
}
402+
403+
if (handlers && handlers->exception_handlers[vector][ec])
404+
return handlers->exception_handlers[vector][ec](regs);
405+
406+
unexpected_exception:
407+
return kvm_exit_unexpected_exception(vector, ec);
408+
}
409+
410+
void vcpu_init_vector_tables(struct kvm_vcpu *vcpu)
411+
{
412+
extern char exception_vectors;
413+
414+
vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(stvec), (unsigned long)&exception_vectors);
415+
}
416+
417+
void vm_init_vector_tables(struct kvm_vm *vm)
418+
{
419+
vm->handlers = __vm_vaddr_alloc(vm, sizeof(struct handlers),
420+
vm->page_size, MEM_REGION_DATA);
421+
422+
*(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers;
423+
}
424+
425+
void vm_install_exception_handler(struct kvm_vm *vm, int vector, exception_handler_fn handler)
426+
{
427+
struct handlers *handlers = addr_gva2hva(vm, vm->handlers);
428+
429+
assert(vector < NR_EXCEPTIONS);
430+
handlers->exception_handlers[0][vector] = handler;
431+
}
432+
433+
void vm_install_interrupt_handler(struct kvm_vm *vm, exception_handler_fn handler)
434+
{
435+
struct handlers *handlers = addr_gva2hva(vm, vm->handlers);
436+
437+
handlers->exception_handlers[1][0] = handler;
369438
}
370439

371440
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,

0 commit comments

Comments
 (0)