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. */ 15 extern char int_handler[]; 16 asm("int_handler:\n" 17 "j .\n"); 18 19 static 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 42 static 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. */ 56 extern char test_step_pgm_guest_code[]; 57 asm("test_step_pgm_guest_code:\n" 58 ".insn rr,0x1d00,%r1,%r0 /* dr %r1,%r0 */\n" 59 "j .\n"); 60 61 static 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 */ 70 extern char test_step_pgm_diag_guest_code[]; 71 asm("test_step_pgm_diag_guest_code:\n" 72 "diag %r0,%r0,0\n" 73 "j .\n"); 74 75 static 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 */ 102 extern char test_step_pgm_iske_guest_code[]; 103 asm("test_step_pgm_iske_guest_code:\n" 104 "iske %r2,%r2\n" 105 "j .\n"); 106 107 static 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 */ 116 extern char test_step_pgm_lctl_guest_code[]; 117 asm("test_step_pgm_lctl_guest_code:\n" 118 "lctl %c0,%c0,1\n" 119 "j .\n"); 120 121 static 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. */ 127 extern char test_step_svc_guest_code[]; 128 asm("test_step_svc_guest_code:\n" 129 "svc 0\n" 130 "j .\n"); 131 132 static 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. */ 138 static 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 149 int 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.