All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ricardo Koller <ricarkol@google.com>
To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu
Cc: pbonzini@redhat.com, maz@kernel.org, drjones@redhat.com,
	alexandru.elisei@arm.com, eric.auger@redhat.com,
	Ricardo Koller <ricarkol@google.com>
Subject: [PATCH 1/3] KVM: selftests: Add exception handling support for aarch64
Date: Thu, 22 Apr 2021 21:03:49 -0700	[thread overview]
Message-ID: <20210423040351.1132218-2-ricarkol@google.com> (raw)
In-Reply-To: <20210423040351.1132218-1-ricarkol@google.com>

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_handle_exception with a (vector, error-code)
tuple. The unhandled exception reporting from the guest is done using
the new ucall UCALL_UNHANDLED.

Signed-off-by: Ricardo Koller <ricarkol@google.com>
---
 tools/testing/selftests/kvm/Makefile          |   2 +-
 .../selftests/kvm/include/aarch64/processor.h |  69 ++++++++++++
 .../testing/selftests/kvm/include/kvm_util.h  |   1 +
 .../selftests/kvm/lib/aarch64/handlers.S      | 104 ++++++++++++++++++
 .../selftests/kvm/lib/aarch64/processor.c     |  56 ++++++++++
 5 files changed, 231 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..5c902ad95c35 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,71 @@ 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 pc;
+	u64 pstate;
+	u64 sp;
+	u64 lr;
+	u64 regs[31];
+};
+
+#define VECTOR_NUM	16
+
+enum {
+	VECTOR_SYNC_EL1_SP0,
+	VECTOR_IRQ_EL1_SP0,
+	VECTOR_FIQ_EL1_SP0,
+	VECTOR_ERROR_EL1_SP0,
+
+	VECTOR_SYNC_EL1,
+	VECTOR_IRQ_EL1,
+	VECTOR_FIQ_EL1,
+	VECTOR_ERROR_EL1,
+
+	VECTOR_SYNC_EL0_64,
+	VECTOR_IRQ_EL0_64,
+	VECTOR_FIQ_EL0_64,
+	VECTOR_ERROR_EL0_64,
+
+	VECTOR_SYNC_EL0_32,
+	VECTOR_IRQ_EL0_32,
+	VECTOR_FIQ_EL0_32,
+	VECTOR_ERROR_EL0_32,
+};
+
+/* Some common EC (Exception classes) */
+#define ESR_EC_ILLEGAL_INS	0x0e
+#define ESR_EC_SVC64		0x15
+#define ESR_EC_IABORT_EL1	0x21
+#define ESR_EC_DABORT_EL1	0x25
+#define ESR_EC_SERROR		0x2f
+#define ESR_EC_HW_BP_EL1	0x31
+#define ESR_EC_SSTEP_EL1	0x33
+#define ESR_EC_WP_EL1		0x35
+#define ESR_EC_BRK_INS		0x3C
+
+#define ESR_EC_NUM		64
+
+#define ESR_EC_SHIFT		26
+#define ESR_EC_MASK		0x3f
+
+void vm_init_descriptor_tables(struct kvm_vm *vm);
+void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid);
+void vm_handle_exception(struct kvm_vm *vm, int vector, int ec,
+			void (*handler)(struct ex_regs *));
+
+#define SPSR_D          (1 << 9)
+#define SPSR_SS         (1 << 21)
+
+#define write_sysreg(reg, val)						  \
+({									  \
+	asm volatile("msr "__stringify(reg)", %0" : : "r"(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/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index bea4644d645d..7880929ea548 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -347,6 +347,7 @@ enum {
 	UCALL_SYNC,
 	UCALL_ABORT,
 	UCALL_DONE,
+	UCALL_UNHANDLED,
 };
 
 #define UCALL_MAX_ARGS 6
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..c920679b87c0
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/aarch64/handlers.S
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+.macro save_registers, el
+	stp	x28, x29, [sp, #-16]!
+	stp	x26, x27, [sp, #-16]!
+	stp	x24, x25, [sp, #-16]!
+	stp	x22, x23, [sp, #-16]!
+	stp	x20, x21, [sp, #-16]!
+	stp	x18, x19, [sp, #-16]!
+	stp	x16, x17, [sp, #-16]!
+	stp	x14, x15, [sp, #-16]!
+	stp	x12, x13, [sp, #-16]!
+	stp	x10, x11, [sp, #-16]!
+	stp	x8, x9, [sp, #-16]!
+	stp	x6, x7, [sp, #-16]!
+	stp	x4, x5, [sp, #-16]!
+	stp	x2, x3, [sp, #-16]!
+	stp	x0, x1, [sp, #-16]!
+
+	.if \el == 0
+	mrs	x1, sp_el0
+	.else
+	mov	x1, sp
+	.endif
+	stp	x1, lr, [sp, #-16]! /* SP, LR */
+
+	mrs	x1, elr_el1
+	mrs	x2, spsr_el1
+	stp	x1, x2, [sp, #-16]! /* PC, PSTATE */
+.endm
+
+.macro restore_registers, el
+	ldp	x1, x2, [sp], #16 /* PC, PSTATE */
+	msr	elr_el1, x1
+	msr	spsr_el1, x2
+
+	ldp	x1, lr, [sp], #16 /* SP, LR */
+	.if \el == 0
+	msr	sp_el0, x1
+	.endif
+
+	ldp	x0, x1, [sp], #16
+	ldp	x2, x3, [sp], #16
+	ldp	x4, x5, [sp], #16
+	ldp	x6, x7, [sp], #16
+	ldp	x8, x9, [sp], #16
+	ldp	x10, x11, [sp], #16
+	ldp	x12, x13, [sp], #16
+	ldp	x14, x15, [sp], #16
+	ldp	x16, x17, [sp], #16
+	ldp	x18, x19, [sp], #16
+	ldp	x20, x21, [sp], #16
+	ldp	x22, x23, [sp], #16
+	ldp	x24, x25, [sp], #16
+	ldp	x26, x27, [sp], #16
+	ldp	x28, x29, [sp], #16
+
+	eret
+.endm
+
+.pushsection ".entry.text", "ax"
+.balign 0x800
+.global vectors
+vectors:
+.popsection
+
+/*
+ * Build an exception handler for vector and append a jump to it into
+ * vectors (while making sure that it's 0x80 aligned).
+ */
+.macro HANDLER, el, label, vector
+handler\()\vector:
+	save_registers \el
+	mov	x0, sp
+	mov	x1, \vector
+	bl	route_exception
+	restore_registers \el
+
+.pushsection ".entry.text", "ax"
+.balign 0x80
+	b	handler\()\vector
+.popsection
+.endm
+
+.global ex_handler_code
+ex_handler_code:
+	HANDLER	1, sync, 0			// Synchronous EL1t
+	HANDLER	1, irq, 1			// IRQ EL1t
+	HANDLER	1, fiq, 2			// FIQ EL1t
+	HANDLER	1, error, 3			// Error EL1t
+
+	HANDLER	1, sync, 4			// Synchronous EL1h
+	HANDLER	1, irq, 5			// IRQ EL1h
+	HANDLER	1, fiq, 6			// FIQ EL1h
+	HANDLER	1, error, 7			// Error EL1h
+
+	HANDLER	0, sync, 8			// Synchronous 64-bit EL0
+	HANDLER	0, irq, 9			// IRQ 64-bit EL0
+	HANDLER	0, fiq, 10			// FIQ 64-bit EL0
+	HANDLER	0, error, 11			// Error 64-bit EL0
+
+	HANDLER	0, sync, 12			// Synchronous 32-bit EL0
+	HANDLER	0, irq, 13			// IRQ 32-bit EL0
+	HANDLER	0, fiq, 14			// FIQ 32-bit EL0
+	HANDLER	0, error, 15			// 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..286305b561d8 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);
@@ -336,4 +339,57 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...)
 
 void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid)
 {
+	struct ucall uc;
+
+	if (get_ucall(vm, vcpuid, &uc) == UCALL_UNHANDLED) {
+		TEST_ASSERT(false,
+			"Unexpected exception guest (vector:0x%lx, ec:0x%lx)",
+			uc.args[0], uc.args[1]);
+	}
+}
+
+void kvm_exit_unexpected_vector(int vector, uint64_t ec)
+{
+	ucall(UCALL_UNHANDLED, 2, vector, ec);
+}
+
+#define HANDLERS_IDX(_vector, _ec)	((_vector * ESR_EC_NUM) + _ec)
+
+void vm_init_descriptor_tables(struct kvm_vm *vm)
+{
+	vm->handlers = vm_vaddr_alloc(vm,
+			VECTOR_NUM * ESR_EC_NUM * sizeof(void *),
+			vm->page_size, 0, 0);
+	*(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers;
+}
+
+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 route_exception(struct ex_regs *regs, int vector)
+{
+	typedef void(*handler)(struct ex_regs *);
+	uint64_t esr = read_sysreg(esr_el1);
+	uint64_t ec = (esr >> ESR_EC_SHIFT) & ESR_EC_MASK;
+
+	handler *handlers = (handler *)exception_handlers;
+
+	if (handlers && handlers[HANDLERS_IDX(vector, ec)])
+		handlers[HANDLERS_IDX(vector, ec)](regs);
+	else
+		kvm_exit_unexpected_vector(vector, ec);
+}
+
+void vm_handle_exception(struct kvm_vm *vm, int vector, int ec,
+			 void (*handler)(struct ex_regs *))
+{
+	vm_vaddr_t *handlers = (vm_vaddr_t *)addr_gva2hva(vm, vm->handlers);
+
+	assert(vector < VECTOR_NUM);
+	assert(ec < ESR_EC_NUM);
+	handlers[HANDLERS_IDX(vector, ec)] = (vm_vaddr_t)handler;
 }
-- 
2.31.1.498.g6c1eba8ee3d-goog


WARNING: multiple messages have this Message-ID (diff)
From: Ricardo Koller <ricarkol@google.com>
To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu
Cc: maz@kernel.org, pbonzini@redhat.com
Subject: [PATCH 1/3] KVM: selftests: Add exception handling support for aarch64
Date: Thu, 22 Apr 2021 21:03:49 -0700	[thread overview]
Message-ID: <20210423040351.1132218-2-ricarkol@google.com> (raw)
In-Reply-To: <20210423040351.1132218-1-ricarkol@google.com>

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_handle_exception with a (vector, error-code)
tuple. The unhandled exception reporting from the guest is done using
the new ucall UCALL_UNHANDLED.

Signed-off-by: Ricardo Koller <ricarkol@google.com>
---
 tools/testing/selftests/kvm/Makefile          |   2 +-
 .../selftests/kvm/include/aarch64/processor.h |  69 ++++++++++++
 .../testing/selftests/kvm/include/kvm_util.h  |   1 +
 .../selftests/kvm/lib/aarch64/handlers.S      | 104 ++++++++++++++++++
 .../selftests/kvm/lib/aarch64/processor.c     |  56 ++++++++++
 5 files changed, 231 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..5c902ad95c35 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,71 @@ 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 pc;
+	u64 pstate;
+	u64 sp;
+	u64 lr;
+	u64 regs[31];
+};
+
+#define VECTOR_NUM	16
+
+enum {
+	VECTOR_SYNC_EL1_SP0,
+	VECTOR_IRQ_EL1_SP0,
+	VECTOR_FIQ_EL1_SP0,
+	VECTOR_ERROR_EL1_SP0,
+
+	VECTOR_SYNC_EL1,
+	VECTOR_IRQ_EL1,
+	VECTOR_FIQ_EL1,
+	VECTOR_ERROR_EL1,
+
+	VECTOR_SYNC_EL0_64,
+	VECTOR_IRQ_EL0_64,
+	VECTOR_FIQ_EL0_64,
+	VECTOR_ERROR_EL0_64,
+
+	VECTOR_SYNC_EL0_32,
+	VECTOR_IRQ_EL0_32,
+	VECTOR_FIQ_EL0_32,
+	VECTOR_ERROR_EL0_32,
+};
+
+/* Some common EC (Exception classes) */
+#define ESR_EC_ILLEGAL_INS	0x0e
+#define ESR_EC_SVC64		0x15
+#define ESR_EC_IABORT_EL1	0x21
+#define ESR_EC_DABORT_EL1	0x25
+#define ESR_EC_SERROR		0x2f
+#define ESR_EC_HW_BP_EL1	0x31
+#define ESR_EC_SSTEP_EL1	0x33
+#define ESR_EC_WP_EL1		0x35
+#define ESR_EC_BRK_INS		0x3C
+
+#define ESR_EC_NUM		64
+
+#define ESR_EC_SHIFT		26
+#define ESR_EC_MASK		0x3f
+
+void vm_init_descriptor_tables(struct kvm_vm *vm);
+void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid);
+void vm_handle_exception(struct kvm_vm *vm, int vector, int ec,
+			void (*handler)(struct ex_regs *));
+
+#define SPSR_D          (1 << 9)
+#define SPSR_SS         (1 << 21)
+
+#define write_sysreg(reg, val)						  \
+({									  \
+	asm volatile("msr "__stringify(reg)", %0" : : "r"(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/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index bea4644d645d..7880929ea548 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -347,6 +347,7 @@ enum {
 	UCALL_SYNC,
 	UCALL_ABORT,
 	UCALL_DONE,
+	UCALL_UNHANDLED,
 };
 
 #define UCALL_MAX_ARGS 6
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..c920679b87c0
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/aarch64/handlers.S
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+.macro save_registers, el
+	stp	x28, x29, [sp, #-16]!
+	stp	x26, x27, [sp, #-16]!
+	stp	x24, x25, [sp, #-16]!
+	stp	x22, x23, [sp, #-16]!
+	stp	x20, x21, [sp, #-16]!
+	stp	x18, x19, [sp, #-16]!
+	stp	x16, x17, [sp, #-16]!
+	stp	x14, x15, [sp, #-16]!
+	stp	x12, x13, [sp, #-16]!
+	stp	x10, x11, [sp, #-16]!
+	stp	x8, x9, [sp, #-16]!
+	stp	x6, x7, [sp, #-16]!
+	stp	x4, x5, [sp, #-16]!
+	stp	x2, x3, [sp, #-16]!
+	stp	x0, x1, [sp, #-16]!
+
+	.if \el == 0
+	mrs	x1, sp_el0
+	.else
+	mov	x1, sp
+	.endif
+	stp	x1, lr, [sp, #-16]! /* SP, LR */
+
+	mrs	x1, elr_el1
+	mrs	x2, spsr_el1
+	stp	x1, x2, [sp, #-16]! /* PC, PSTATE */
+.endm
+
+.macro restore_registers, el
+	ldp	x1, x2, [sp], #16 /* PC, PSTATE */
+	msr	elr_el1, x1
+	msr	spsr_el1, x2
+
+	ldp	x1, lr, [sp], #16 /* SP, LR */
+	.if \el == 0
+	msr	sp_el0, x1
+	.endif
+
+	ldp	x0, x1, [sp], #16
+	ldp	x2, x3, [sp], #16
+	ldp	x4, x5, [sp], #16
+	ldp	x6, x7, [sp], #16
+	ldp	x8, x9, [sp], #16
+	ldp	x10, x11, [sp], #16
+	ldp	x12, x13, [sp], #16
+	ldp	x14, x15, [sp], #16
+	ldp	x16, x17, [sp], #16
+	ldp	x18, x19, [sp], #16
+	ldp	x20, x21, [sp], #16
+	ldp	x22, x23, [sp], #16
+	ldp	x24, x25, [sp], #16
+	ldp	x26, x27, [sp], #16
+	ldp	x28, x29, [sp], #16
+
+	eret
+.endm
+
+.pushsection ".entry.text", "ax"
+.balign 0x800
+.global vectors
+vectors:
+.popsection
+
+/*
+ * Build an exception handler for vector and append a jump to it into
+ * vectors (while making sure that it's 0x80 aligned).
+ */
+.macro HANDLER, el, label, vector
+handler\()\vector:
+	save_registers \el
+	mov	x0, sp
+	mov	x1, \vector
+	bl	route_exception
+	restore_registers \el
+
+.pushsection ".entry.text", "ax"
+.balign 0x80
+	b	handler\()\vector
+.popsection
+.endm
+
+.global ex_handler_code
+ex_handler_code:
+	HANDLER	1, sync, 0			// Synchronous EL1t
+	HANDLER	1, irq, 1			// IRQ EL1t
+	HANDLER	1, fiq, 2			// FIQ EL1t
+	HANDLER	1, error, 3			// Error EL1t
+
+	HANDLER	1, sync, 4			// Synchronous EL1h
+	HANDLER	1, irq, 5			// IRQ EL1h
+	HANDLER	1, fiq, 6			// FIQ EL1h
+	HANDLER	1, error, 7			// Error EL1h
+
+	HANDLER	0, sync, 8			// Synchronous 64-bit EL0
+	HANDLER	0, irq, 9			// IRQ 64-bit EL0
+	HANDLER	0, fiq, 10			// FIQ 64-bit EL0
+	HANDLER	0, error, 11			// Error 64-bit EL0
+
+	HANDLER	0, sync, 12			// Synchronous 32-bit EL0
+	HANDLER	0, irq, 13			// IRQ 32-bit EL0
+	HANDLER	0, fiq, 14			// FIQ 32-bit EL0
+	HANDLER	0, error, 15			// 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..286305b561d8 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);
@@ -336,4 +339,57 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...)
 
 void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid)
 {
+	struct ucall uc;
+
+	if (get_ucall(vm, vcpuid, &uc) == UCALL_UNHANDLED) {
+		TEST_ASSERT(false,
+			"Unexpected exception guest (vector:0x%lx, ec:0x%lx)",
+			uc.args[0], uc.args[1]);
+	}
+}
+
+void kvm_exit_unexpected_vector(int vector, uint64_t ec)
+{
+	ucall(UCALL_UNHANDLED, 2, vector, ec);
+}
+
+#define HANDLERS_IDX(_vector, _ec)	((_vector * ESR_EC_NUM) + _ec)
+
+void vm_init_descriptor_tables(struct kvm_vm *vm)
+{
+	vm->handlers = vm_vaddr_alloc(vm,
+			VECTOR_NUM * ESR_EC_NUM * sizeof(void *),
+			vm->page_size, 0, 0);
+	*(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers;
+}
+
+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 route_exception(struct ex_regs *regs, int vector)
+{
+	typedef void(*handler)(struct ex_regs *);
+	uint64_t esr = read_sysreg(esr_el1);
+	uint64_t ec = (esr >> ESR_EC_SHIFT) & ESR_EC_MASK;
+
+	handler *handlers = (handler *)exception_handlers;
+
+	if (handlers && handlers[HANDLERS_IDX(vector, ec)])
+		handlers[HANDLERS_IDX(vector, ec)](regs);
+	else
+		kvm_exit_unexpected_vector(vector, ec);
+}
+
+void vm_handle_exception(struct kvm_vm *vm, int vector, int ec,
+			 void (*handler)(struct ex_regs *))
+{
+	vm_vaddr_t *handlers = (vm_vaddr_t *)addr_gva2hva(vm, vm->handlers);
+
+	assert(vector < VECTOR_NUM);
+	assert(ec < ESR_EC_NUM);
+	handlers[HANDLERS_IDX(vector, ec)] = (vm_vaddr_t)handler;
 }
-- 
2.31.1.498.g6c1eba8ee3d-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

  reply	other threads:[~2021-04-23  4:04 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-23  4:03 [PATCH 0/3] KVM: selftests: arm64 exception handling and debug test Ricardo Koller
2021-04-23  4:03 ` Ricardo Koller
2021-04-23  4:03 ` Ricardo Koller [this message]
2021-04-23  4:03   ` [PATCH 1/3] KVM: selftests: Add exception handling support for aarch64 Ricardo Koller
2021-04-23  8:58   ` Marc Zyngier
2021-04-23  8:58     ` Marc Zyngier
2021-04-23 11:05     ` Andrew Jones
2021-04-23 11:05       ` Andrew Jones
2021-04-26 18:58       ` Ricardo Koller
2021-04-26 18:58         ` Ricardo Koller
2021-04-29 17:51     ` Ricardo Koller
2021-04-29 17:51       ` Ricardo Koller
2021-04-29 19:59       ` Marc Zyngier
2021-04-29 19:59         ` Marc Zyngier
2021-04-29 20:48         ` Ricardo Koller
2021-04-29 20:48           ` Ricardo Koller
2021-04-23  4:03 ` [PATCH 2/3] KVM: selftests: Add aarch64/debug-exceptions test Ricardo Koller
2021-04-23  4:03   ` Ricardo Koller
2021-04-23 11:22   ` Andrew Jones
2021-04-23 11:22     ` Andrew Jones
2021-04-23  4:03 ` [PATCH 3/3] KVM: selftests: Use a ucall for x86 unhandled vector reporting Ricardo Koller
2021-04-23  4:03   ` Ricardo Koller
2021-04-23 10:45   ` Andrew Jones
2021-04-23 10:45     ` Andrew Jones

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210423040351.1132218-2-ricarkol@google.com \
    --to=ricarkol@google.com \
    --cc=alexandru.elisei@arm.com \
    --cc=drjones@redhat.com \
    --cc=eric.auger@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=maz@kernel.org \
    --cc=pbonzini@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.