Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: selftests: sync_regs test for diag318

The DIAGNOSE 0x0318 instruction, unique to s390x, is a privileged call
that must be intercepted via SIE, handled in userspace, and the
information set by the instruction is communicated back to KVM.

To test the instruction interception, an ad-hoc handler is defined which
simply has a VM execute the instruction and then userspace will extract
the necessary info. The handler is defined such that the instruction
invocation occurs only once. It is up to the caller to determine how the
info returned by this handler should be used.

The diag318 info is communicated from userspace to KVM via a sync_regs
call. This is tested during a sync_regs test, where the diag318 info is
requested via the handler, then the info is stored in the appropriate
register in KVM via a sync registers call.

If KVM does not support diag318, then the tests will print a message
stating that diag318 was skipped, and the asserts will simply test
against a value of 0.

Signed-off-by: Collin Walling <walling@linux.ibm.com>
Link: https://lore.kernel.org/r/20201207154125.10322-1-walling@linux.ibm.com
Acked-by: Janosch Frank <frankja@linux.ibm.com>
Acked-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>

authored by

Collin Walling and committed by
Christian Borntraeger
efaa83a3 0cd2a787

+111 -2
+1 -1
tools/testing/selftests/kvm/Makefile
··· 36 36 LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c lib/test_util.c 37 37 LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/svm.c lib/x86_64/ucall.c 38 38 LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c 39 - LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c 39 + LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c 40 40 41 41 TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test 42 42 TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
+13
tools/testing/selftests/kvm/include/s390x/diag318_test_handler.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later 2 + * 3 + * Test handler for the s390x DIAGNOSE 0x0318 instruction. 4 + * 5 + * Copyright (C) 2020, IBM 6 + */ 7 + 8 + #ifndef SELFTEST_KVM_DIAG318_TEST_HANDLER 9 + #define SELFTEST_KVM_DIAG318_TEST_HANDLER 10 + 11 + uint64_t get_diag318_info(void); 12 + 13 + #endif
+82
tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Test handler for the s390x DIAGNOSE 0x0318 instruction. 4 + * 5 + * Copyright (C) 2020, IBM 6 + */ 7 + 8 + #include "test_util.h" 9 + #include "kvm_util.h" 10 + 11 + #define VCPU_ID 6 12 + 13 + #define ICPT_INSTRUCTION 0x04 14 + #define IPA0_DIAG 0x8300 15 + 16 + static void guest_code(void) 17 + { 18 + uint64_t diag318_info = 0x12345678; 19 + 20 + asm volatile ("diag %0,0,0x318\n" : : "d" (diag318_info)); 21 + } 22 + 23 + /* 24 + * The DIAGNOSE 0x0318 instruction call must be handled via userspace. As such, 25 + * we create an ad-hoc VM here to handle the instruction then extract the 26 + * necessary data. It is up to the caller to decide what to do with that data. 27 + */ 28 + static uint64_t diag318_handler(void) 29 + { 30 + struct kvm_vm *vm; 31 + struct kvm_run *run; 32 + uint64_t reg; 33 + uint64_t diag318_info; 34 + 35 + vm = vm_create_default(VCPU_ID, 0, guest_code); 36 + vcpu_run(vm, VCPU_ID); 37 + run = vcpu_state(vm, VCPU_ID); 38 + 39 + TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, 40 + "DIAGNOSE 0x0318 instruction was not intercepted"); 41 + TEST_ASSERT(run->s390_sieic.icptcode == ICPT_INSTRUCTION, 42 + "Unexpected intercept code: 0x%x", run->s390_sieic.icptcode); 43 + TEST_ASSERT((run->s390_sieic.ipa & 0xff00) == IPA0_DIAG, 44 + "Unexpected IPA0 code: 0x%x", (run->s390_sieic.ipa & 0xff00)); 45 + 46 + reg = (run->s390_sieic.ipa & 0x00f0) >> 4; 47 + diag318_info = run->s.regs.gprs[reg]; 48 + 49 + TEST_ASSERT(diag318_info != 0, "DIAGNOSE 0x0318 info not set"); 50 + 51 + kvm_vm_free(vm); 52 + 53 + return diag318_info; 54 + } 55 + 56 + uint64_t get_diag318_info(void) 57 + { 58 + static uint64_t diag318_info; 59 + static bool printed_skip; 60 + 61 + /* 62 + * If KVM does not support diag318, then return 0 to 63 + * ensure tests do not break. 64 + */ 65 + if (!kvm_check_cap(KVM_CAP_S390_DIAG318)) { 66 + if (!printed_skip) { 67 + fprintf(stdout, "KVM_CAP_S390_DIAG318 not supported. " 68 + "Skipping diag318 test.\n"); 69 + printed_skip = true; 70 + } 71 + return 0; 72 + } 73 + 74 + /* 75 + * If a test has previously requested the diag318 info, 76 + * then don't bother spinning up a temporary VM again. 77 + */ 78 + if (!diag318_info) 79 + diag318_info = diag318_handler(); 80 + 81 + return diag318_info; 82 + }
+15 -1
tools/testing/selftests/kvm/s390x/sync_regs_test.c
··· 20 20 21 21 #include "test_util.h" 22 22 #include "kvm_util.h" 23 + #include "diag318_test_handler.h" 23 24 24 25 #define VCPU_ID 5 25 26 ··· 71 70 72 71 #undef REG_COMPARE 73 72 74 - #define TEST_SYNC_FIELDS (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS) 73 + #define TEST_SYNC_FIELDS (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS|KVM_SYNC_DIAG318) 75 74 #define INVALID_SYNC_FIELD 0x80000000 76 75 77 76 int main(int argc, char *argv[]) ··· 153 152 154 153 run->kvm_valid_regs = TEST_SYNC_FIELDS; 155 154 run->kvm_dirty_regs = KVM_SYNC_GPRS | KVM_SYNC_ACRS; 155 + 156 + if (get_diag318_info() > 0) { 157 + run->s.regs.diag318 = get_diag318_info(); 158 + run->kvm_dirty_regs |= KVM_SYNC_DIAG318; 159 + } 160 + 156 161 rv = _vcpu_run(vm, VCPU_ID); 157 162 TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); 158 163 TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, ··· 171 164 TEST_ASSERT(run->s.regs.acrs[0] == 1 << 11, 172 165 "acr0 sync regs value incorrect 0x%x.", 173 166 run->s.regs.acrs[0]); 167 + TEST_ASSERT(run->s.regs.diag318 == get_diag318_info(), 168 + "diag318 sync regs value incorrect 0x%llx.", 169 + run->s.regs.diag318); 174 170 175 171 vcpu_regs_get(vm, VCPU_ID, &regs); 176 172 compare_regs(&regs, &run->s.regs); ··· 187 177 run->kvm_valid_regs = TEST_SYNC_FIELDS; 188 178 run->kvm_dirty_regs = 0; 189 179 run->s.regs.gprs[11] = 0xDEADBEEF; 180 + run->s.regs.diag318 = 0x4B1D; 190 181 rv = _vcpu_run(vm, VCPU_ID); 191 182 TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); 192 183 TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, ··· 197 186 TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF, 198 187 "r11 sync regs value incorrect 0x%llx.", 199 188 run->s.regs.gprs[11]); 189 + TEST_ASSERT(run->s.regs.diag318 != 0x4B1D, 190 + "diag318 sync regs value incorrect 0x%llx.", 191 + run->s.regs.diag318); 200 192 201 193 kvm_vm_free(vm); 202 194