| 1 | |
| 2 |
|
| 3 | #include "kvm_util.h"
|
| 4 | #include "test_util.h"
|
| 5 | #include "sie.h"
|
| 6 |
|
| 7 | #include <linux/kvm.h>
|
| 8 |
|
| 9 | #define __LC_SVC_NEW_PSW 0x1c0
|
| 10 | #define __LC_PGM_NEW_PSW 0x1d0
|
| 11 | #define IPA0_DIAG 0x8300
|
| 12 | #define PGM_SPECIFICATION 0x06
|
| 13 |
|
| 14 |
|
| 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, u64 *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] = (u64)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 | u64 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 |
|
| 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 | u64 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_INST);
|
| 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 |
|
| 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 |
|
| 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 | }
|