1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Test for s390x CPU resets 4 * 5 * Copyright (C) 2020, IBM 6 */ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <sys/ioctl.h> 12 13 #include "test_util.h" 14 #include "kvm_util.h" 15 16 #define VCPU_ID 3 17 #define LOCAL_IRQS 32 18 19 struct kvm_s390_irq buf[VCPU_ID + LOCAL_IRQS]; 20 21 struct kvm_vm *vm; 22 struct kvm_run *run; 23 struct kvm_sync_regs *regs; 24 static uint64_t regs_null[16]; 25 26 static uint64_t crs[16] = { 0x40000ULL, 27 0x42000ULL, 28 0, 0, 0, 0, 0, 29 0x43000ULL, 30 0, 0, 0, 0, 0, 31 0x44000ULL, 32 0, 0 33 }; 34 35 static void guest_code_initial(void) 36 { 37 /* Round toward 0 */ 38 uint32_t fpc = 0x11; 39 40 /* Dirty registers */ 41 asm volatile ( 42 " lctlg 0,15,%0\n" 43 " sfpc %1\n" 44 : : "Q" (crs), "d" (fpc)); 45 GUEST_SYNC(0); 46 } 47 48 static void test_one_reg(uint64_t id, uint64_t value) 49 { 50 struct kvm_one_reg reg; 51 uint64_t eval_reg; 52 53 reg.addr = (uintptr_t)&eval_reg; 54 reg.id = id; 55 vcpu_get_reg(vm, VCPU_ID, ®); 56 TEST_ASSERT(eval_reg == value, "value == %s", value); 57 } 58 59 static void assert_noirq(void) 60 { 61 struct kvm_s390_irq_state irq_state; 62 int irqs; 63 64 irq_state.len = sizeof(buf); 65 irq_state.buf = (unsigned long)buf; 66 irqs = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_GET_IRQ_STATE, &irq_state); 67 /* 68 * irqs contains the number of retrieved interrupts. Any interrupt 69 * (notably, the emergency call interrupt we have injected) should 70 * be cleared by the resets, so this should be 0. 71 */ 72 TEST_ASSERT(irqs >= 0, "Could not fetch IRQs: errno %d\n", errno); 73 TEST_ASSERT(!irqs, "IRQ pending"); 74 } 75 76 static void assert_clear(void) 77 { 78 struct kvm_sregs sregs; 79 struct kvm_regs regs; 80 struct kvm_fpu fpu; 81 82 vcpu_regs_get(vm, VCPU_ID, ®s); 83 TEST_ASSERT(!memcmp(®s.gprs, regs_null, sizeof(regs.gprs)), "grs == 0"); 84 85 vcpu_sregs_get(vm, VCPU_ID, &sregs); 86 TEST_ASSERT(!memcmp(&sregs.acrs, regs_null, sizeof(sregs.acrs)), "acrs == 0"); 87 88 vcpu_fpu_get(vm, VCPU_ID, &fpu); 89 TEST_ASSERT(!memcmp(&fpu.fprs, regs_null, sizeof(fpu.fprs)), "fprs == 0"); 90 } 91 92 static void assert_initial(void) 93 { 94 struct kvm_sregs sregs; 95 struct kvm_fpu fpu; 96 97 vcpu_sregs_get(vm, VCPU_ID, &sregs); 98 TEST_ASSERT(sregs.crs[0] == 0xE0UL, "cr0 == 0xE0"); 99 TEST_ASSERT(sregs.crs[14] == 0xC2000000UL, "cr14 == 0xC2000000"); 100 TEST_ASSERT(!memcmp(&sregs.crs[1], regs_null, sizeof(sregs.crs[1]) * 12), 101 "cr1-13 == 0"); 102 TEST_ASSERT(sregs.crs[15] == 0, "cr15 == 0"); 103 104 vcpu_fpu_get(vm, VCPU_ID, &fpu); 105 TEST_ASSERT(!fpu.fpc, "fpc == 0"); 106 107 test_one_reg(KVM_REG_S390_GBEA, 1); 108 test_one_reg(KVM_REG_S390_PP, 0); 109 test_one_reg(KVM_REG_S390_TODPR, 0); 110 test_one_reg(KVM_REG_S390_CPU_TIMER, 0); 111 test_one_reg(KVM_REG_S390_CLOCK_COMP, 0); 112 } 113 114 static void assert_normal(void) 115 { 116 test_one_reg(KVM_REG_S390_PFTOKEN, KVM_S390_PFAULT_TOKEN_INVALID); 117 assert_noirq(); 118 } 119 120 static void inject_irq(int cpu_id) 121 { 122 struct kvm_s390_irq_state irq_state; 123 struct kvm_s390_irq *irq = &buf[0]; 124 int irqs; 125 126 /* Inject IRQ */ 127 irq_state.len = sizeof(struct kvm_s390_irq); 128 irq_state.buf = (unsigned long)buf; 129 irq->type = KVM_S390_INT_EMERGENCY; 130 irq->u.emerg.code = cpu_id; 131 irqs = _vcpu_ioctl(vm, cpu_id, KVM_S390_SET_IRQ_STATE, &irq_state); 132 TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d\n", errno); 133 } 134 135 static void test_normal(void) 136 { 137 printf("Testing normal reset\n"); 138 /* Create VM */ 139 vm = vm_create_default(VCPU_ID, 0, guest_code_initial); 140 run = vcpu_state(vm, VCPU_ID); 141 regs = &run->s.regs; 142 143 vcpu_run(vm, VCPU_ID); 144 145 inject_irq(VCPU_ID); 146 147 vcpu_ioctl(vm, VCPU_ID, KVM_S390_NORMAL_RESET, 0); 148 assert_normal(); 149 kvm_vm_free(vm); 150 } 151 152 static void test_initial(void) 153 { 154 printf("Testing initial reset\n"); 155 vm = vm_create_default(VCPU_ID, 0, guest_code_initial); 156 run = vcpu_state(vm, VCPU_ID); 157 regs = &run->s.regs; 158 159 vcpu_run(vm, VCPU_ID); 160 161 inject_irq(VCPU_ID); 162 163 vcpu_ioctl(vm, VCPU_ID, KVM_S390_INITIAL_RESET, 0); 164 assert_normal(); 165 assert_initial(); 166 kvm_vm_free(vm); 167 } 168 169 static void test_clear(void) 170 { 171 printf("Testing clear reset\n"); 172 vm = vm_create_default(VCPU_ID, 0, guest_code_initial); 173 run = vcpu_state(vm, VCPU_ID); 174 regs = &run->s.regs; 175 176 vcpu_run(vm, VCPU_ID); 177 178 inject_irq(VCPU_ID); 179 180 vcpu_ioctl(vm, VCPU_ID, KVM_S390_CLEAR_RESET, 0); 181 assert_normal(); 182 assert_initial(); 183 assert_clear(); 184 kvm_vm_free(vm); 185 } 186 187 int main(int argc, char *argv[]) 188 { 189 setbuf(stdout, NULL); /* Tell stdout not to buffer its content */ 190 191 test_initial(); 192 if (kvm_check_cap(KVM_CAP_S390_VCPU_RESETS)) { 193 test_normal(); 194 test_clear(); 195 } 196 return 0; 197 } 198