1// SPDX-License-Identifier: GPL-2.0-only 2/* Test KVM debugging features. */ 3#include "kvm_util.h" 4#include "test_util.h" 5 6#include <linux/kvm.h> 7 8#define __LC_SVC_NEW_PSW 0x1c0 9#define __LC_PGM_NEW_PSW 0x1d0 10#define ICPT_INSTRUCTION 0x04 11#define IPA0_DIAG 0x8300 12#define PGM_SPECIFICATION 0x06 13 14/* Common code for testing single-stepping interruptions. */ 15extern char int_handler[]; 16asm("int_handler:\n" 17 "j .\n"); 18 19static struct kvm_vm *test_step_int_1(struct kvm_vcpu **vcpu, void *guest_code, 20 size_t new_psw_off, uint64_t *new_psw) 21{ 22 struct kvm_guest_debug debug = {}; 23 struct kvm_regs regs; 24 struct kvm_vm *vm; 25 char *lowcore; 26 27 vm = vm_create_with_one_vcpu(vcpu, guest_code); 28 lowcore = addr_gpa2hva(vm, 0); 29 new_psw[0] = (*vcpu)->run->psw_mask; 30 new_psw[1] = (uint64_t)int_handler; 31 memcpy(lowcore + new_psw_off, new_psw, 16); 32 vcpu_regs_get(*vcpu, ®s); 33 regs.gprs[2] = -1; 34 vcpu_regs_set(*vcpu, ®s); 35 debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; 36 vcpu_guest_debug_set(*vcpu, &debug); 37 vcpu_run(*vcpu); 38 39 return vm; 40} 41 42static void test_step_int(void *guest_code, size_t new_psw_off) 43{ 44 struct kvm_vcpu *vcpu; 45 uint64_t new_psw[2]; 46 struct kvm_vm *vm; 47 48 vm = test_step_int_1(&vcpu, guest_code, new_psw_off, new_psw); 49 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_DEBUG); 50 TEST_ASSERT_EQ(vcpu->run->psw_mask, new_psw[0]); 51 TEST_ASSERT_EQ(vcpu->run->psw_addr, new_psw[1]); 52 kvm_vm_free(vm); 53} 54 55/* Test single-stepping "boring" program interruptions. */ 56extern char test_step_pgm_guest_code[]; 57asm("test_step_pgm_guest_code:\n" 58 ".insn rr,0x1d00,%r1,%r0 /* dr %r1,%r0 */\n" 59 "j .\n"); 60 61static void test_step_pgm(void) 62{ 63 test_step_int(test_step_pgm_guest_code, __LC_PGM_NEW_PSW); 64} 65 66/* 67 * Test single-stepping program interruptions caused by DIAG. 68 * Userspace emulation must not interfere with single-stepping. 69 */ 70extern char test_step_pgm_diag_guest_code[]; 71asm("test_step_pgm_diag_guest_code:\n" 72 "diag %r0,%r0,0\n" 73 "j .\n"); 74 75static void test_step_pgm_diag(void) 76{ 77 struct kvm_s390_irq irq = { 78 .type = KVM_S390_PROGRAM_INT, 79 .u.pgm.code = PGM_SPECIFICATION, 80 }; 81 struct kvm_vcpu *vcpu; 82 uint64_t new_psw[2]; 83 struct kvm_vm *vm; 84 85 vm = test_step_int_1(&vcpu, test_step_pgm_diag_guest_code, 86 __LC_PGM_NEW_PSW, new_psw); 87 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); 88 TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_INSTRUCTION); 89 TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa & 0xff00, IPA0_DIAG); 90 vcpu_ioctl(vcpu, KVM_S390_IRQ, &irq); 91 vcpu_run(vcpu); 92 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_DEBUG); 93 TEST_ASSERT_EQ(vcpu->run->psw_mask, new_psw[0]); 94 TEST_ASSERT_EQ(vcpu->run->psw_addr, new_psw[1]); 95 kvm_vm_free(vm); 96} 97 98/* 99 * Test single-stepping program interruptions caused by ISKE. 100 * CPUSTAT_KSS handling must not interfere with single-stepping. 101 */ 102extern char test_step_pgm_iske_guest_code[]; 103asm("test_step_pgm_iske_guest_code:\n" 104 "iske %r2,%r2\n" 105 "j .\n"); 106 107static void test_step_pgm_iske(void) 108{ 109 test_step_int(test_step_pgm_iske_guest_code, __LC_PGM_NEW_PSW); 110} 111 112/* 113 * Test single-stepping program interruptions caused by LCTL. 114 * KVM emulation must not interfere with single-stepping. 115 */ 116extern char test_step_pgm_lctl_guest_code[]; 117asm("test_step_pgm_lctl_guest_code:\n" 118 "lctl %c0,%c0,1\n" 119 "j .\n"); 120 121static void test_step_pgm_lctl(void) 122{ 123 test_step_int(test_step_pgm_lctl_guest_code, __LC_PGM_NEW_PSW); 124} 125 126/* Test single-stepping supervisor-call interruptions. */ 127extern char test_step_svc_guest_code[]; 128asm("test_step_svc_guest_code:\n" 129 "svc 0\n" 130 "j .\n"); 131 132static void test_step_svc(void) 133{ 134 test_step_int(test_step_svc_guest_code, __LC_SVC_NEW_PSW); 135} 136 137/* Run all tests above. */ 138static struct testdef { 139 const char *name; 140 void (*test)(void); 141} testlist[] = { 142 { "single-step pgm", test_step_pgm }, 143 { "single-step pgm caused by diag", test_step_pgm_diag }, 144 { "single-step pgm caused by iske", test_step_pgm_iske }, 145 { "single-step pgm caused by lctl", test_step_pgm_lctl }, 146 { "single-step svc", test_step_svc }, 147}; 148 149int main(int argc, char *argv[]) 150{ 151 int idx; 152 153 ksft_print_header(); 154 ksft_set_plan(ARRAY_SIZE(testlist)); 155 for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) { 156 testlist[idx].test(); 157 ksft_test_result_pass("%s\n", testlist[idx].name); 158 } 159 ksft_finished(); 160} 161