Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Test handler for the s390x DIAGNOSE 0x0318 instruction.
0004  *
0005  * Copyright (C) 2020, IBM
0006  */
0007 
0008 #include "test_util.h"
0009 #include "kvm_util.h"
0010 
0011 #define ICPT_INSTRUCTION    0x04
0012 #define IPA0_DIAG       0x8300
0013 
0014 static void guest_code(void)
0015 {
0016     uint64_t diag318_info = 0x12345678;
0017 
0018     asm volatile ("diag %0,0,0x318\n" : : "d" (diag318_info));
0019 }
0020 
0021 /*
0022  * The DIAGNOSE 0x0318 instruction call must be handled via userspace. As such,
0023  * we create an ad-hoc VM here to handle the instruction then extract the
0024  * necessary data. It is up to the caller to decide what to do with that data.
0025  */
0026 static uint64_t diag318_handler(void)
0027 {
0028     struct kvm_vcpu *vcpu;
0029     struct kvm_vm *vm;
0030     struct kvm_run *run;
0031     uint64_t reg;
0032     uint64_t diag318_info;
0033 
0034     vm = vm_create_with_one_vcpu(&vcpu, guest_code);
0035     vcpu_run(vcpu);
0036     run = vcpu->run;
0037 
0038     TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
0039             "DIAGNOSE 0x0318 instruction was not intercepted");
0040     TEST_ASSERT(run->s390_sieic.icptcode == ICPT_INSTRUCTION,
0041             "Unexpected intercept code: 0x%x", run->s390_sieic.icptcode);
0042     TEST_ASSERT((run->s390_sieic.ipa & 0xff00) == IPA0_DIAG,
0043             "Unexpected IPA0 code: 0x%x", (run->s390_sieic.ipa & 0xff00));
0044 
0045     reg = (run->s390_sieic.ipa & 0x00f0) >> 4;
0046     diag318_info = run->s.regs.gprs[reg];
0047 
0048     TEST_ASSERT(diag318_info != 0, "DIAGNOSE 0x0318 info not set");
0049 
0050     kvm_vm_free(vm);
0051 
0052     return diag318_info;
0053 }
0054 
0055 uint64_t get_diag318_info(void)
0056 {
0057     static uint64_t diag318_info;
0058     static bool printed_skip;
0059 
0060     /*
0061      * If KVM does not support diag318, then return 0 to
0062      * ensure tests do not break.
0063      */
0064     if (!kvm_has_cap(KVM_CAP_S390_DIAG318)) {
0065         if (!printed_skip) {
0066             fprintf(stdout, "KVM_CAP_S390_DIAG318 not supported. "
0067                 "Skipping diag318 test.\n");
0068             printed_skip = true;
0069         }
0070         return 0;
0071     }
0072 
0073     /*
0074      * If a test has previously requested the diag318 info,
0075      * then don't bother spinning up a temporary VM again.
0076      */
0077     if (!diag318_info)
0078         diag318_info = diag318_handler();
0079 
0080     return diag318_info;
0081 }