KVM: s390: Fixes and cleanups for 5.6 - fix register corruption - ENOTSUPP/EOPNOTSUPP mixed - reset cleanups/fixes - selftests
Unified · Split
| @@ -4177,6 +4177,42 @@ This ioctl issues an ultravisor call to terminate the secure guest, · 4176 unmodified lines | ||
| 4177 | 4177 | unpins the VPA pages and releases all the device pages that are used to |
| 4178 | 4178 | track the secure pages by hypervisor. |
| 4179 | 4179 | |
| 4180 | +4.122 KVM_S390_NORMAL_RESET | |
| 4181 | + | |
| 4182 | +Capability: KVM_CAP_S390_VCPU_RESETS | |
| 4183 | +Architectures: s390 | |
| 4184 | +Type: vcpu ioctl | |
| 4185 | +Parameters: none | |
| 4186 | +Returns: 0 | |
| 4187 | + | |
| 4188 | +This ioctl resets VCPU registers and control structures according to | |
| 4189 | +the cpu reset definition in the POP (Principles Of Operation). | |
| 4190 | + | |
| 4191 | +4.123 KVM_S390_INITIAL_RESET | |
| 4192 | + | |
| 4193 | +Capability: none | |
| 4194 | +Architectures: s390 | |
| 4195 | +Type: vcpu ioctl | |
| 4196 | +Parameters: none | |
| 4197 | +Returns: 0 | |
| 4198 | + | |
| 4199 | +This ioctl resets VCPU registers and control structures according to | |
| 4200 | +the initial cpu reset definition in the POP. However, the cpu is not | |
| 4201 | +put into ESA mode. This reset is a superset of the normal reset. | |
| 4202 | + | |
| 4203 | +4.124 KVM_S390_CLEAR_RESET | |
| 4204 | + | |
| 4205 | +Capability: KVM_CAP_S390_VCPU_RESETS | |
| 4206 | +Architectures: s390 | |
| 4207 | +Type: vcpu ioctl | |
| 4208 | +Parameters: none | |
| 4209 | +Returns: 0 | |
| 4210 | + | |
| 4211 | +This ioctl resets VCPU registers and control structures according to | |
| 4212 | +the clear cpu reset definition in the POP. However, the cpu is not put | |
| 4213 | +into ESA mode. This reset is a superset of the initial reset. | |
| 4214 | + | |
| 4215 | + | |
| 4180 | 4216 | 5. The kvm_run structure |
| 4181 | 4217 | ------------------------ |
| 4182 | 4218 | |
| @@ -5405,3 +5441,10 @@ handling by KVM (as some KVM hypercall may be mistakenly treated as TLB · 1222 unmodified lines | ||
| 5405 | 5441 | flush hypercalls by Hyper-V) so userspace should disable KVM identification |
| 5406 | 5442 | in CPUID and only exposes Hyper-V identification. In this case, guest |
| 5407 | 5443 | thinks it's running on Hyper-V and only use Hyper-V hypercalls. |
| 5444 | + | |
| 5445 | +8.22 KVM_CAP_S390_VCPU_RESETS | |
| 5446 | + | |
| 5447 | +Architectures: s390 | |
| 5448 | + | |
| 5449 | +This capability indicates that the KVM_S390_NORMAL_RESET and | |
| 5450 | +KVM_S390_CLEAR_RESET ioctls are available. | |
| @@ -122,6 +122,11 @@ struct mcck_volatile_info { · 121 unmodified lines | ||
| 122 | 122 | __u32 reserved; |
| 123 | 123 | }; |
| 124 | 124 | |
| 125 | +#define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \ | |
| 126 | + CR0_MEASUREMENT_ALERT_SUBMASK) | |
| 127 | +#define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \ | |
| 128 | + CR14_EXTERNAL_DAMAGE_SUBMASK) | |
| 129 | + | |
| 125 | 130 | #define CPUSTAT_STOPPED 0x80000000 |
| 126 | 131 | #define CPUSTAT_WAIT 0x10000000 |
| 127 | 132 | #define CPUSTAT_ECALL_PEND 0x08000000 |
| @@ -2190,7 +2190,7 @@ static int flic_ais_mode_get_all(struct kvm *kvm, struct kvm_device_attr *attr) · 2189 unmodified lines | ||
| 2190 | 2190 | return -EINVAL; |
| 2191 | 2191 | |
| 2192 | 2192 | if (!test_kvm_facility(kvm, 72)) |
| 2193 | − return -ENOTSUPP; | |
| 2193 | + return -EOPNOTSUPP; | |
| 2194 | 2194 | |
| 2195 | 2195 | mutex_lock(&fi->ais_lock); |
| 2196 | 2196 | ais.simm = fi->simm; |
| @@ -2499,7 +2499,7 @@ static int modify_ais_mode(struct kvm *kvm, struct kvm_device_attr *attr) · 302 unmodified lines | ||
| 2499 | 2499 | int ret = 0; |
| 2500 | 2500 | |
| 2501 | 2501 | if (!test_kvm_facility(kvm, 72)) |
| 2502 | − return -ENOTSUPP; | |
| 2502 | + return -EOPNOTSUPP; | |
| 2503 | 2503 | |
| 2504 | 2504 | if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req))) |
| 2505 | 2505 | return -EFAULT; |
| @@ -2579,7 +2579,7 @@ static int flic_ais_mode_set_all(struct kvm *kvm, struct kvm_device_attr *attr) · 73 unmodified lines | ||
| 2579 | 2579 | struct kvm_s390_ais_all ais; |
| 2580 | 2580 | |
| 2581 | 2581 | if (!test_kvm_facility(kvm, 72)) |
| 2582 | − return -ENOTSUPP; | |
| 2582 | + return -EOPNOTSUPP; | |
| 2583 | 2583 | |
| 2584 | 2584 | if (copy_from_user(&ais, (void __user *)attr->addr, sizeof(ais))) |
| 2585 | 2585 | return -EFAULT; |
| @@ -529,6 +529,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) · 528 unmodified lines | ||
| 529 | 529 | case KVM_CAP_S390_CMMA_MIGRATION: |
| 530 | 530 | case KVM_CAP_S390_AIS: |
| 531 | 531 | case KVM_CAP_S390_AIS_MIGRATION: |
| 532 | + case KVM_CAP_S390_VCPU_RESETS: | |
| 532 | 533 | r = 1; |
| 533 | 534 | break; |
| 534 | 535 | case KVM_CAP_S390_HPAGE_1M: |
| @@ -2808,35 +2809,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) · 2273 unmodified lines | ||
| 2808 | 2809 | |
| 2809 | 2810 | } |
| 2810 | 2811 | |
| 2811 | −static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) | |
| 2812 | −{ | |
| 2813 | − /* this equals initial cpu reset in pop, but we don't switch to ESA */ | |
| 2814 | − vcpu->arch.sie_block->gpsw.mask = 0UL; | |
| 2815 | − vcpu->arch.sie_block->gpsw.addr = 0UL; | |
| 2816 | − kvm_s390_set_prefix(vcpu, 0); | |
| 2817 | − kvm_s390_set_cpu_timer(vcpu, 0); | |
| 2818 | − vcpu->arch.sie_block->ckc = 0UL; | |
| 2819 | − vcpu->arch.sie_block->todpr = 0; | |
| 2820 | − memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64)); | |
| 2821 | − vcpu->arch.sie_block->gcr[0] = CR0_UNUSED_56 | | |
| 2822 | − CR0_INTERRUPT_KEY_SUBMASK | | |
| 2823 | − CR0_MEASUREMENT_ALERT_SUBMASK; | |
| 2824 | − vcpu->arch.sie_block->gcr[14] = CR14_UNUSED_32 | | |
| 2825 | − CR14_UNUSED_33 | | |
| 2826 | − CR14_EXTERNAL_DAMAGE_SUBMASK; | |
| 2827 | − /* make sure the new fpc will be lazily loaded */ | |
| 2828 | − save_fpu_regs(); | |
| 2829 | − current->thread.fpu.fpc = 0; | |
| 2830 | − vcpu->arch.sie_block->gbea = 1; | |
| 2831 | − vcpu->arch.sie_block->pp = 0; | |
| 2832 | − vcpu->arch.sie_block->fpf &= ~FPF_BPBC; | |
| 2833 | − vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; | |
| 2834 | − kvm_clear_async_pf_completion_queue(vcpu); | |
| 2835 | − if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) | |
| 2836 | − kvm_s390_vcpu_stop(vcpu); | |
| 2837 | − kvm_s390_clear_local_irqs(vcpu); | |
| 2838 | −} | |
| 2839 | − | |
| 2840 | 2812 | void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) |
| 2841 | 2813 | { |
| 2842 | 2814 | mutex_lock(&vcpu->kvm->lock); |
| @@ -3279,10 +3251,53 @@ static int kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, · 436 unmodified lines | ||
| 3279 | 3251 | return r; |
| 3280 | 3252 | } |
| 3281 | 3253 | |
| 3282 | −static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) | |
| 3254 | +static void kvm_arch_vcpu_ioctl_normal_reset(struct kvm_vcpu *vcpu) | |
| 3283 | 3255 | { |
| 3284 | − kvm_s390_vcpu_initial_reset(vcpu); | |
| 3285 | − return 0; | |
| 3256 | + vcpu->arch.sie_block->gpsw.mask &= ~PSW_MASK_RI; | |
| 3257 | + vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; | |
| 3258 | + memset(vcpu->run->s.regs.riccb, 0, sizeof(vcpu->run->s.regs.riccb)); | |
| 3259 | + | |
| 3260 | + kvm_clear_async_pf_completion_queue(vcpu); | |
| 3261 | + if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) | |
| 3262 | + kvm_s390_vcpu_stop(vcpu); | |
| 3263 | + kvm_s390_clear_local_irqs(vcpu); | |
| 3264 | +} | |
| 3265 | + | |
| 3266 | +static void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) | |
| 3267 | +{ | |
| 3268 | + /* Initial reset is a superset of the normal reset */ | |
| 3269 | + kvm_arch_vcpu_ioctl_normal_reset(vcpu); | |
| 3270 | + | |
| 3271 | + /* this equals initial cpu reset in pop, but we don't switch to ESA */ | |
| 3272 | + vcpu->arch.sie_block->gpsw.mask = 0; | |
| 3273 | + vcpu->arch.sie_block->gpsw.addr = 0; | |
| 3274 | + kvm_s390_set_prefix(vcpu, 0); | |
| 3275 | + kvm_s390_set_cpu_timer(vcpu, 0); | |
| 3276 | + vcpu->arch.sie_block->ckc = 0; | |
| 3277 | + vcpu->arch.sie_block->todpr = 0; | |
| 3278 | + memset(vcpu->arch.sie_block->gcr, 0, sizeof(vcpu->arch.sie_block->gcr)); | |
| 3279 | + vcpu->arch.sie_block->gcr[0] = CR0_INITIAL_MASK; | |
| 3280 | + vcpu->arch.sie_block->gcr[14] = CR14_INITIAL_MASK; | |
| 3281 | + vcpu->run->s.regs.fpc = 0; | |
| 3282 | + vcpu->arch.sie_block->gbea = 1; | |
| 3283 | + vcpu->arch.sie_block->pp = 0; | |
| 3284 | + vcpu->arch.sie_block->fpf &= ~FPF_BPBC; | |
| 3285 | +} | |
| 3286 | + | |
| 3287 | +static void kvm_arch_vcpu_ioctl_clear_reset(struct kvm_vcpu *vcpu) | |
| 3288 | +{ | |
| 3289 | + struct kvm_sync_regs *regs = &vcpu->run->s.regs; | |
| 3290 | + | |
| 3291 | + /* Clear reset is a superset of the initial reset */ | |
| 3292 | + kvm_arch_vcpu_ioctl_initial_reset(vcpu); | |
| 3293 | + | |
| 3294 | + memset(®s->gprs, 0, sizeof(regs->gprs)); | |
| 3295 | + memset(®s->vrs, 0, sizeof(regs->vrs)); | |
| 3296 | + memset(®s->acrs, 0, sizeof(regs->acrs)); | |
| 3297 | + memset(®s->gscb, 0, sizeof(regs->gscb)); | |
| 3298 | + | |
| 3299 | + regs->etoken = 0; | |
| 3300 | + regs->etoken_extension = 0; | |
| 3286 | 3301 | } |
| 3287 | 3302 | |
| 3288 | 3303 | int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) |
| @@ -4343,7 +4358,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, · 1054 unmodified lines | ||
| 4343 | 4358 | switch (ioctl) { |
| 4344 | 4359 | case KVM_S390_STORE_STATUS: |
| 4345 | 4360 | idx = srcu_read_lock(&vcpu->kvm->srcu); |
| 4346 | − r = kvm_s390_vcpu_store_status(vcpu, arg); | |
| 4361 | + r = kvm_s390_store_status_unloaded(vcpu, arg); | |
| 4347 | 4362 | srcu_read_unlock(&vcpu->kvm->srcu, idx); |
| 4348 | 4363 | break; |
| 4349 | 4364 | case KVM_S390_SET_INITIAL_PSW: { |
| @@ -4355,8 +4370,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp, · 5 unmodified lines | ||
| 4355 | 4370 | r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw); |
| 4356 | 4371 | break; |
| 4357 | 4372 | } |
| 4373 | + case KVM_S390_CLEAR_RESET: | |
| 4374 | + r = 0; | |
| 4375 | + kvm_arch_vcpu_ioctl_clear_reset(vcpu); | |
| 4376 | + break; | |
| 4358 | 4377 | case KVM_S390_INITIAL_RESET: |
| 4359 | − r = kvm_arch_vcpu_ioctl_initial_reset(vcpu); | |
| 4378 | + r = 0; | |
| 4379 | + kvm_arch_vcpu_ioctl_initial_reset(vcpu); | |
| 4380 | + break; | |
| 4381 | + case KVM_S390_NORMAL_RESET: | |
| 4382 | + r = 0; | |
| 4383 | + kvm_arch_vcpu_ioctl_normal_reset(vcpu); | |
| 4360 | 4384 | break; |
| 4361 | 4385 | case KVM_SET_ONE_REG: |
| 4362 | 4386 | case KVM_GET_ONE_REG: { |
| @@ -1009,6 +1009,7 @@ struct kvm_ppc_resize_hpt { · 1008 unmodified lines | ||
| 1009 | 1009 | #define KVM_CAP_PPC_GUEST_DEBUG_SSTEP 176 |
| 1010 | 1010 | #define KVM_CAP_ARM_NISV_TO_USER 177 |
| 1011 | 1011 | #define KVM_CAP_ARM_INJECT_EXT_DABT 178 |
| 1012 | +#define KVM_CAP_S390_VCPU_RESETS 179 | |
| 1012 | 1013 | |
| 1013 | 1014 | #ifdef KVM_CAP_IRQ_ROUTING |
| 1014 | 1015 | |
| @@ -1473,6 +1474,10 @@ struct kvm_enc_region { · 458 unmodified lines | ||
| 1473 | 1474 | /* Available with KVM_CAP_ARM_SVE */ |
| 1474 | 1475 | #define KVM_ARM_VCPU_FINALIZE _IOW(KVMIO, 0xc2, int) |
| 1475 | 1476 | |
| 1477 | +/* Available with KVM_CAP_S390_VCPU_RESETS */ | |
| 1478 | +#define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3) | |
| 1479 | +#define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4) | |
| 1480 | + | |
| 1476 | 1481 | /* Secure Encrypted Virtualization command */ |
| 1477 | 1482 | enum sev_cmd_id { |
| 1478 | 1483 | /* Guest initialization commands */ |
| @@ -36,6 +36,7 @@ TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus · 35 unmodified lines | ||
| 36 | 36 | |
| 37 | 37 | TEST_GEN_PROGS_s390x = s390x/memop |
| 38 | 38 | TEST_GEN_PROGS_s390x += s390x/sync_regs_test |
| 39 | +TEST_GEN_PROGS_s390x += s390x/resets | |
| 39 | 40 | TEST_GEN_PROGS_s390x += dirty_log_test |
| 40 | 41 | TEST_GEN_PROGS_s390x += kvm_create_max_vcpus |
| 41 | 42 | |
| @@ -125,6 +125,12 @@ void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, · 124 unmodified lines | ||
| 125 | 125 | struct kvm_sregs *sregs); |
| 126 | 126 | int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, |
| 127 | 127 | struct kvm_sregs *sregs); |
| 128 | +void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, | |
| 129 | + struct kvm_fpu *fpu); | |
| 130 | +void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, | |
| 131 | + struct kvm_fpu *fpu); | |
| 132 | +void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg); | |
| 133 | +void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg); | |
| 128 | 134 | #ifdef __KVM_HAVE_VCPU_EVENTS |
| 129 | 135 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, |
| 130 | 136 | struct kvm_vcpu_events *events); |
| @@ -1373,6 +1373,42 @@ int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) · 1372 unmodified lines | ||
| 1373 | 1373 | return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); |
| 1374 | 1374 | } |
| 1375 | 1375 | |
| 1376 | +void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) | |
| 1377 | +{ | |
| 1378 | + int ret; | |
| 1379 | + | |
| 1380 | + ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_FPU, fpu); | |
| 1381 | + TEST_ASSERT(ret == 0, "KVM_GET_FPU failed, rc: %i errno: %i (%s)", | |
| 1382 | + ret, errno, strerror(errno)); | |
| 1383 | +} | |
| 1384 | + | |
| 1385 | +void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) | |
| 1386 | +{ | |
| 1387 | + int ret; | |
| 1388 | + | |
| 1389 | + ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_FPU, fpu); | |
| 1390 | + TEST_ASSERT(ret == 0, "KVM_SET_FPU failed, rc: %i errno: %i (%s)", | |
| 1391 | + ret, errno, strerror(errno)); | |
| 1392 | +} | |
| 1393 | + | |
| 1394 | +void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) | |
| 1395 | +{ | |
| 1396 | + int ret; | |
| 1397 | + | |
| 1398 | + ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, reg); | |
| 1399 | + TEST_ASSERT(ret == 0, "KVM_GET_ONE_REG failed, rc: %i errno: %i (%s)", | |
| 1400 | + ret, errno, strerror(errno)); | |
| 1401 | +} | |
| 1402 | + | |
| 1403 | +void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) | |
| 1404 | +{ | |
| 1405 | + int ret; | |
| 1406 | + | |
| 1407 | + ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, reg); | |
| 1408 | + TEST_ASSERT(ret == 0, "KVM_SET_ONE_REG failed, rc: %i errno: %i (%s)", | |
| 1409 | + ret, errno, strerror(errno)); | |
| 1410 | +} | |
| 1411 | + | |
| 1376 | 1412 | /* |
| 1377 | 1413 | * VCPU Ioctl |
| 1378 | 1414 | * |
| @@ -0,0 +1,197 @@ | ||
| 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 | +} | |