84 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			84 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * RISC-V KVM ebreak test.
 | |
|  *
 | |
|  * Copyright 2024 Beijing ESWIN Computing Technology Co., Ltd.
 | |
|  *
 | |
|  */
 | |
| #include "kvm_util.h"
 | |
| #include "ucall_common.h"
 | |
| 
 | |
| #define LABEL_ADDRESS(v) ((uint64_t)&(v))
 | |
| 
 | |
| extern unsigned char sw_bp_1, sw_bp_2;
 | |
| static uint64_t sw_bp_addr;
 | |
| 
 | |
| static void guest_code(void)
 | |
| {
 | |
| 	asm volatile(
 | |
| 		".option push\n"
 | |
| 		".option norvc\n"
 | |
| 		"sw_bp_1: ebreak\n"
 | |
| 		"sw_bp_2: ebreak\n"
 | |
| 		".option pop\n"
 | |
| 	);
 | |
| 	GUEST_ASSERT_EQ(READ_ONCE(sw_bp_addr), LABEL_ADDRESS(sw_bp_2));
 | |
| 
 | |
| 	GUEST_DONE();
 | |
| }
 | |
| 
 | |
| static void guest_breakpoint_handler(struct ex_regs *regs)
 | |
| {
 | |
| 	WRITE_ONCE(sw_bp_addr, regs->epc);
 | |
| 	regs->epc += 4;
 | |
| }
 | |
| 
 | |
| int main(void)
 | |
| {
 | |
| 	struct kvm_vm *vm;
 | |
| 	struct kvm_vcpu *vcpu;
 | |
| 	uint64_t pc;
 | |
| 	struct kvm_guest_debug debug = {
 | |
| 		.control = KVM_GUESTDBG_ENABLE,
 | |
| 	};
 | |
| 
 | |
| 	TEST_REQUIRE(kvm_has_cap(KVM_CAP_SET_GUEST_DEBUG));
 | |
| 
 | |
| 	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
 | |
| 
 | |
| 	vm_init_vector_tables(vm);
 | |
| 	vcpu_init_vector_tables(vcpu);
 | |
| 	vm_install_exception_handler(vm, EXC_BREAKPOINT,
 | |
| 					guest_breakpoint_handler);
 | |
| 
 | |
| 	/*
 | |
| 	 * Enable the guest debug.
 | |
| 	 * ebreak should exit to the VMM with KVM_EXIT_DEBUG reason.
 | |
| 	 */
 | |
| 	vcpu_guest_debug_set(vcpu, &debug);
 | |
| 	vcpu_run(vcpu);
 | |
| 
 | |
| 	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_DEBUG);
 | |
| 
 | |
| 	vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.pc), &pc);
 | |
| 	TEST_ASSERT_EQ(pc, LABEL_ADDRESS(sw_bp_1));
 | |
| 
 | |
| 	/* skip sw_bp_1 */
 | |
| 	vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.pc), pc + 4);
 | |
| 
 | |
| 	/*
 | |
| 	 * Disable all debug controls.
 | |
| 	 * Guest should handle the ebreak without exiting to the VMM.
 | |
| 	 */
 | |
| 	memset(&debug, 0, sizeof(debug));
 | |
| 	vcpu_guest_debug_set(vcpu, &debug);
 | |
| 
 | |
| 	vcpu_run(vcpu);
 | |
| 
 | |
| 	TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE);
 | |
| 
 | |
| 	kvm_vm_free(vm);
 | |
| 
 | |
| 	return 0;
 | |
| }
 |