Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Test for s390x KVM_CAP_SYNC_REGS
0004  *
0005  * Based on the same test for x86:
0006  * Copyright (C) 2018, Google LLC.
0007  *
0008  * Adaptions for s390x:
0009  * Copyright (C) 2019, Red Hat, Inc.
0010  *
0011  * Test expected behavior of the KVM_CAP_SYNC_REGS functionality.
0012  */
0013 
0014 #define _GNU_SOURCE /* for program_invocation_short_name */
0015 #include <fcntl.h>
0016 #include <stdio.h>
0017 #include <stdlib.h>
0018 #include <string.h>
0019 #include <sys/ioctl.h>
0020 
0021 #include "test_util.h"
0022 #include "kvm_util.h"
0023 #include "diag318_test_handler.h"
0024 #include "kselftest.h"
0025 
0026 static void guest_code(void)
0027 {
0028     /*
0029      * We embed diag 501 here instead of doing a ucall to avoid that
0030      * the compiler has messed with r11 at the time of the ucall.
0031      */
0032     asm volatile (
0033         "0: diag 0,0,0x501\n"
0034         "   ahi 11,1\n"
0035         "   j 0b\n"
0036     );
0037 }
0038 
0039 #define REG_COMPARE(reg) \
0040     TEST_ASSERT(left->reg == right->reg, \
0041             "Register " #reg \
0042             " values did not match: 0x%llx, 0x%llx\n", \
0043             left->reg, right->reg)
0044 
0045 #define REG_COMPARE32(reg) \
0046     TEST_ASSERT(left->reg == right->reg, \
0047             "Register " #reg \
0048             " values did not match: 0x%x, 0x%x\n", \
0049             left->reg, right->reg)
0050 
0051 
0052 static void compare_regs(struct kvm_regs *left, struct kvm_sync_regs *right)
0053 {
0054     int i;
0055 
0056     for (i = 0; i < 16; i++)
0057         REG_COMPARE(gprs[i]);
0058 }
0059 
0060 static void compare_sregs(struct kvm_sregs *left, struct kvm_sync_regs *right)
0061 {
0062     int i;
0063 
0064     for (i = 0; i < 16; i++)
0065         REG_COMPARE32(acrs[i]);
0066 
0067     for (i = 0; i < 16; i++)
0068         REG_COMPARE(crs[i]);
0069 }
0070 
0071 #undef REG_COMPARE
0072 
0073 #define TEST_SYNC_FIELDS   (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS|KVM_SYNC_DIAG318)
0074 #define INVALID_SYNC_FIELD 0x80000000
0075 
0076 void test_read_invalid(struct kvm_vcpu *vcpu)
0077 {
0078     struct kvm_run *run = vcpu->run;
0079     int rv;
0080 
0081     /* Request reading invalid register set from VCPU. */
0082     run->kvm_valid_regs = INVALID_SYNC_FIELD;
0083     rv = _vcpu_run(vcpu);
0084     TEST_ASSERT(rv < 0 && errno == EINVAL,
0085             "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
0086             rv);
0087     run->kvm_valid_regs = 0;
0088 
0089     run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
0090     rv = _vcpu_run(vcpu);
0091     TEST_ASSERT(rv < 0 && errno == EINVAL,
0092             "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
0093             rv);
0094     run->kvm_valid_regs = 0;
0095 }
0096 
0097 void test_set_invalid(struct kvm_vcpu *vcpu)
0098 {
0099     struct kvm_run *run = vcpu->run;
0100     int rv;
0101 
0102     /* Request setting invalid register set into VCPU. */
0103     run->kvm_dirty_regs = INVALID_SYNC_FIELD;
0104     rv = _vcpu_run(vcpu);
0105     TEST_ASSERT(rv < 0 && errno == EINVAL,
0106             "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
0107             rv);
0108     run->kvm_dirty_regs = 0;
0109 
0110     run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
0111     rv = _vcpu_run(vcpu);
0112     TEST_ASSERT(rv < 0 && errno == EINVAL,
0113             "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
0114             rv);
0115     run->kvm_dirty_regs = 0;
0116 }
0117 
0118 void test_req_and_verify_all_valid_regs(struct kvm_vcpu *vcpu)
0119 {
0120     struct kvm_run *run = vcpu->run;
0121     struct kvm_sregs sregs;
0122     struct kvm_regs regs;
0123     int rv;
0124 
0125     /* Request and verify all valid register sets. */
0126     run->kvm_valid_regs = TEST_SYNC_FIELDS;
0127     rv = _vcpu_run(vcpu);
0128     TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
0129     TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
0130             "Unexpected exit reason: %u (%s)\n",
0131             run->exit_reason,
0132             exit_reason_str(run->exit_reason));
0133     TEST_ASSERT(run->s390_sieic.icptcode == 4 &&
0134             (run->s390_sieic.ipa >> 8) == 0x83 &&
0135             (run->s390_sieic.ipb >> 16) == 0x501,
0136             "Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x\n",
0137             run->s390_sieic.icptcode, run->s390_sieic.ipa,
0138             run->s390_sieic.ipb);
0139 
0140     vcpu_regs_get(vcpu, &regs);
0141     compare_regs(&regs, &run->s.regs);
0142 
0143     vcpu_sregs_get(vcpu, &sregs);
0144     compare_sregs(&sregs, &run->s.regs);
0145 }
0146 
0147 void test_set_and_verify_various_reg_values(struct kvm_vcpu *vcpu)
0148 {
0149     struct kvm_run *run = vcpu->run;
0150     struct kvm_sregs sregs;
0151     struct kvm_regs regs;
0152     int rv;
0153 
0154     /* Set and verify various register values */
0155     run->s.regs.gprs[11] = 0xBAD1DEA;
0156     run->s.regs.acrs[0] = 1 << 11;
0157 
0158     run->kvm_valid_regs = TEST_SYNC_FIELDS;
0159     run->kvm_dirty_regs = KVM_SYNC_GPRS | KVM_SYNC_ACRS;
0160 
0161     if (get_diag318_info() > 0) {
0162         run->s.regs.diag318 = get_diag318_info();
0163         run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
0164     }
0165 
0166     rv = _vcpu_run(vcpu);
0167     TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
0168     TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
0169             "Unexpected exit reason: %u (%s)\n",
0170             run->exit_reason,
0171             exit_reason_str(run->exit_reason));
0172     TEST_ASSERT(run->s.regs.gprs[11] == 0xBAD1DEA + 1,
0173             "r11 sync regs value incorrect 0x%llx.",
0174             run->s.regs.gprs[11]);
0175     TEST_ASSERT(run->s.regs.acrs[0]  == 1 << 11,
0176             "acr0 sync regs value incorrect 0x%x.",
0177             run->s.regs.acrs[0]);
0178     TEST_ASSERT(run->s.regs.diag318 == get_diag318_info(),
0179             "diag318 sync regs value incorrect 0x%llx.",
0180             run->s.regs.diag318);
0181 
0182     vcpu_regs_get(vcpu, &regs);
0183     compare_regs(&regs, &run->s.regs);
0184 
0185     vcpu_sregs_get(vcpu, &sregs);
0186     compare_sregs(&sregs, &run->s.regs);
0187 }
0188 
0189 void test_clear_kvm_dirty_regs_bits(struct kvm_vcpu *vcpu)
0190 {
0191     struct kvm_run *run = vcpu->run;
0192     int rv;
0193 
0194     /* Clear kvm_dirty_regs bits, verify new s.regs values are
0195      * overwritten with existing guest values.
0196      */
0197     run->kvm_valid_regs = TEST_SYNC_FIELDS;
0198     run->kvm_dirty_regs = 0;
0199     run->s.regs.gprs[11] = 0xDEADBEEF;
0200     run->s.regs.diag318 = 0x4B1D;
0201     rv = _vcpu_run(vcpu);
0202     TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv);
0203     TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC,
0204             "Unexpected exit reason: %u (%s)\n",
0205             run->exit_reason,
0206             exit_reason_str(run->exit_reason));
0207     TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF,
0208             "r11 sync regs value incorrect 0x%llx.",
0209             run->s.regs.gprs[11]);
0210     TEST_ASSERT(run->s.regs.diag318 != 0x4B1D,
0211             "diag318 sync regs value incorrect 0x%llx.",
0212             run->s.regs.diag318);
0213 }
0214 
0215 struct testdef {
0216     const char *name;
0217     void (*test)(struct kvm_vcpu *vcpu);
0218 } testlist[] = {
0219     { "read invalid", test_read_invalid },
0220     { "set invalid", test_set_invalid },
0221     { "request+verify all valid regs", test_req_and_verify_all_valid_regs },
0222     { "set+verify various regs", test_set_and_verify_various_reg_values },
0223     { "clear kvm_dirty_regs bits", test_clear_kvm_dirty_regs_bits },
0224 };
0225 
0226 int main(int argc, char *argv[])
0227 {
0228     struct kvm_vcpu *vcpu;
0229     struct kvm_vm *vm;
0230     int idx;
0231 
0232     TEST_REQUIRE(kvm_has_cap(KVM_CAP_SYNC_REGS));
0233 
0234     /* Tell stdout not to buffer its content */
0235     setbuf(stdout, NULL);
0236 
0237     ksft_print_header();
0238 
0239     ksft_set_plan(ARRAY_SIZE(testlist));
0240 
0241     /* Create VM */
0242     vm = vm_create_with_one_vcpu(&vcpu, guest_code);
0243 
0244     for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) {
0245         testlist[idx].test(vcpu);
0246         ksft_test_result_pass("%s\n", testlist[idx].name);
0247     }
0248 
0249     kvm_vm_free(vm);
0250 
0251     ksft_finished();    /* Print results and exit() accordingly */
0252 }