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