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 ICPT_INSTRUCTION 0x04 12 #define IPA0_DIAG 0x8300 13 14 static void guest_code(void) 15 { 16 uint64_t diag318_info = 0x12345678; 17 18 asm volatile ("diag %0,0,0x318\n" : : "d" (diag318_info)); 19 } 20 21 /* 22 * The DIAGNOSE 0x0318 instruction call must be handled via userspace. As such, 23 * we create an ad-hoc VM here to handle the instruction then extract the 24 * necessary data. It is up to the caller to decide what to do with that data. 25 */ 26 static uint64_t diag318_handler(void) 27 { 28 struct kvm_vcpu *vcpu; 29 struct kvm_vm *vm; 30 struct kvm_run *run; 31 uint64_t reg; 32 uint64_t diag318_info; 33 34 vm = vm_create_with_one_vcpu(&vcpu, guest_code); 35 vcpu_run(vcpu); 36 run = vcpu->run; 37 38 TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, 39 "DIAGNOSE 0x0318 instruction was not intercepted"); 40 TEST_ASSERT(run->s390_sieic.icptcode == ICPT_INSTRUCTION, 41 "Unexpected intercept code: 0x%x", run->s390_sieic.icptcode); 42 TEST_ASSERT((run->s390_sieic.ipa & 0xff00) == IPA0_DIAG, 43 "Unexpected IPA0 code: 0x%x", (run->s390_sieic.ipa & 0xff00)); 44 45 reg = (run->s390_sieic.ipa & 0x00f0) >> 4; 46 diag318_info = run->s.regs.gprs[reg]; 47 48 TEST_ASSERT(diag318_info != 0, "DIAGNOSE 0x0318 info not set"); 49 50 kvm_vm_free(vm); 51 52 return diag318_info; 53 } 54 55 uint64_t get_diag318_info(void) 56 { 57 static uint64_t diag318_info; 58 static bool printed_skip; 59 60 /* 61 * If KVM does not support diag318, then return 0 to 62 * ensure tests do not break. 63 */ 64 if (!kvm_has_cap(KVM_CAP_S390_DIAG318)) { 65 if (!printed_skip) { 66 fprintf(stdout, "KVM_CAP_S390_DIAG318 not supported. " 67 "Skipping diag318 test.\n"); 68 printed_skip = true; 69 } 70 return 0; 71 } 72 73 /* 74 * If a test has previously requested the diag318 info, 75 * then don't bother spinning up a temporary VM again. 76 */ 77 if (!diag318_info) 78 diag318_info = diag318_handler(); 79 80 return diag318_info; 81 } 82