// SPDX-License-Identifier: GPL-2.0-or-later /* * Test handler for the s390x DIAGNOSE 0x0318 instruction. * * Copyright (C) 2020, IBM */ #include "test_util.h" #include "kvm_util.h" #define VCPU_ID 6 #define ICPT_INSTRUCTION 0x04 #define IPA0_DIAG 0x8300 static void guest_code(void) { uint64_t diag318_info = 0x12345678; asm volatile ("diag %0,0,0x318\n" : : "d" (diag318_info)); } /* * The DIAGNOSE 0x0318 instruction call must be handled via userspace. As such, * we create an ad-hoc VM here to handle the instruction then extract the * necessary data. It is up to the caller to decide what to do with that data. */ static uint64_t diag318_handler(void) { struct kvm_vm *vm; struct kvm_run *run; uint64_t reg; uint64_t diag318_info; vm = vm_create_default(VCPU_ID, 0, guest_code); vcpu_run(vm, VCPU_ID); run = vcpu_state(vm, VCPU_ID); TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, "DIAGNOSE 0x0318 instruction was not intercepted"); TEST_ASSERT(run->s390_sieic.icptcode == ICPT_INSTRUCTION, "Unexpected intercept code: 0x%x", run->s390_sieic.icptcode); TEST_ASSERT((run->s390_sieic.ipa & 0xff00) == IPA0_DIAG, "Unexpected IPA0 code: 0x%x", (run->s390_sieic.ipa & 0xff00)); reg = (run->s390_sieic.ipa & 0x00f0) >> 4; diag318_info = run->s.regs.gprs[reg]; TEST_ASSERT(diag318_info != 0, "DIAGNOSE 0x0318 info not set"); kvm_vm_free(vm); return diag318_info; } uint64_t get_diag318_info(void) { static uint64_t diag318_info; static bool printed_skip; /* * If KVM does not support diag318, then return 0 to * ensure tests do not break. */ if (!kvm_check_cap(KVM_CAP_S390_DIAG318)) { if (!printed_skip) { fprintf(stdout, "KVM_CAP_S390_DIAG318 not supported. " "Skipping diag318 test.\n"); printed_skip = true; } return 0; } /* * If a test has previously requested the diag318 info, * then don't bother spinning up a temporary VM again. */ if (!diag318_info) diag318_info = diag318_handler(); return diag318_info; }