linux/tools/testing/selftests/kvm/s390/sync_regs_test.c
Sean Christopherson 67730e6c53 KVM: selftests: Use canonical $(ARCH) paths for KVM selftests directories
Use the kernel's canonical $(ARCH) paths instead of the raw target triple
for KVM selftests directories.  KVM selftests are quite nearly the only
place in the entire kernel that using the target triple for directories,
tools/testing/selftests/drivers/s390x being the lone holdout.

Using the kernel's preferred nomenclature eliminates the minor, but
annoying, friction of having to translate to KVM's selftests directories,
e.g. for pattern matching, opening files, running selftests, etc.

Opportunsitically delete file comments that reference the full path of the
file, as they are obviously prone to becoming stale, and serve no known
purpose.

Reviewed-by: Muhammad Usama Anjum <usama.anjum@collabora.com>
Acked-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Acked-by: Andrew Jones <ajones@ventanamicro.com>
Link: https://lore.kernel.org/r/20241128005547.4077116-16-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
2024-12-18 14:15:04 -08:00

238 lines
6.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Test for s390x KVM_CAP_SYNC_REGS
*
* Based on the same test for x86:
* Copyright (C) 2018, Google LLC.
*
* Adaptions for s390x:
* Copyright (C) 2019, Red Hat, Inc.
*
* Test expected behavior of the KVM_CAP_SYNC_REGS functionality.
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "test_util.h"
#include "kvm_util.h"
#include "diag318_test_handler.h"
#include "kselftest.h"
static void guest_code(void)
{
/*
* We embed diag 501 here instead of doing a ucall to avoid that
* the compiler has messed with r11 at the time of the ucall.
*/
asm volatile (
"0: diag 0,0,0x501\n"
" ahi 11,1\n"
" j 0b\n"
);
}
#define REG_COMPARE(reg) \
TEST_ASSERT(left->reg == right->reg, \
"Register " #reg \
" values did not match: 0x%llx, 0x%llx", \
left->reg, right->reg)
#define REG_COMPARE32(reg) \
TEST_ASSERT(left->reg == right->reg, \
"Register " #reg \
" values did not match: 0x%x, 0x%x", \
left->reg, right->reg)
static void compare_regs(struct kvm_regs *left, struct kvm_sync_regs *right)
{
int i;
for (i = 0; i < 16; i++)
REG_COMPARE(gprs[i]);
}
static void compare_sregs(struct kvm_sregs *left, struct kvm_sync_regs *right)
{
int i;
for (i = 0; i < 16; i++)
REG_COMPARE32(acrs[i]);
for (i = 0; i < 16; i++)
REG_COMPARE(crs[i]);
}
#undef REG_COMPARE
#define TEST_SYNC_FIELDS (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS|KVM_SYNC_DIAG318)
#define INVALID_SYNC_FIELD 0x80000000
void test_read_invalid(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
int rv;
/* Request reading invalid register set from VCPU. */
run->kvm_valid_regs = INVALID_SYNC_FIELD;
rv = _vcpu_run(vcpu);
TEST_ASSERT(rv < 0 && errno == EINVAL,
"Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
rv);
run->kvm_valid_regs = 0;
run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
rv = _vcpu_run(vcpu);
TEST_ASSERT(rv < 0 && errno == EINVAL,
"Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d",
rv);
run->kvm_valid_regs = 0;
}
void test_set_invalid(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
int rv;
/* Request setting invalid register set into VCPU. */
run->kvm_dirty_regs = INVALID_SYNC_FIELD;
rv = _vcpu_run(vcpu);
TEST_ASSERT(rv < 0 && errno == EINVAL,
"Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
rv);
run->kvm_dirty_regs = 0;
run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
rv = _vcpu_run(vcpu);
TEST_ASSERT(rv < 0 && errno == EINVAL,
"Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d",
rv);
run->kvm_dirty_regs = 0;
}
void test_req_and_verify_all_valid_regs(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
struct kvm_sregs sregs;
struct kvm_regs regs;
int rv;
/* Request and verify all valid register sets. */
run->kvm_valid_regs = TEST_SYNC_FIELDS;
rv = _vcpu_run(vcpu);
TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv);
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
TEST_ASSERT(run->s390_sieic.icptcode == 4 &&
(run->s390_sieic.ipa >> 8) == 0x83 &&
(run->s390_sieic.ipb >> 16) == 0x501,
"Unexpected interception code: ic=%u, ipa=0x%x, ipb=0x%x",
run->s390_sieic.icptcode, run->s390_sieic.ipa,
run->s390_sieic.ipb);
vcpu_regs_get(vcpu, &regs);
compare_regs(&regs, &run->s.regs);
vcpu_sregs_get(vcpu, &sregs);
compare_sregs(&sregs, &run->s.regs);
}
void test_set_and_verify_various_reg_values(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
struct kvm_sregs sregs;
struct kvm_regs regs;
int rv;
/* Set and verify various register values */
run->s.regs.gprs[11] = 0xBAD1DEA;
run->s.regs.acrs[0] = 1 << 11;
run->kvm_valid_regs = TEST_SYNC_FIELDS;
run->kvm_dirty_regs = KVM_SYNC_GPRS | KVM_SYNC_ACRS;
if (get_diag318_info() > 0) {
run->s.regs.diag318 = get_diag318_info();
run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
}
rv = _vcpu_run(vcpu);
TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv);
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
TEST_ASSERT(run->s.regs.gprs[11] == 0xBAD1DEA + 1,
"r11 sync regs value incorrect 0x%llx.",
run->s.regs.gprs[11]);
TEST_ASSERT(run->s.regs.acrs[0] == 1 << 11,
"acr0 sync regs value incorrect 0x%x.",
run->s.regs.acrs[0]);
TEST_ASSERT(run->s.regs.diag318 == get_diag318_info(),
"diag318 sync regs value incorrect 0x%llx.",
run->s.regs.diag318);
vcpu_regs_get(vcpu, &regs);
compare_regs(&regs, &run->s.regs);
vcpu_sregs_get(vcpu, &sregs);
compare_sregs(&sregs, &run->s.regs);
}
void test_clear_kvm_dirty_regs_bits(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
int rv;
/* Clear kvm_dirty_regs bits, verify new s.regs values are
* overwritten with existing guest values.
*/
run->kvm_valid_regs = TEST_SYNC_FIELDS;
run->kvm_dirty_regs = 0;
run->s.regs.gprs[11] = 0xDEADBEEF;
run->s.regs.diag318 = 0x4B1D;
rv = _vcpu_run(vcpu);
TEST_ASSERT(rv == 0, "vcpu_run failed: %d", rv);
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
TEST_ASSERT(run->s.regs.gprs[11] != 0xDEADBEEF,
"r11 sync regs value incorrect 0x%llx.",
run->s.regs.gprs[11]);
TEST_ASSERT(run->s.regs.diag318 != 0x4B1D,
"diag318 sync regs value incorrect 0x%llx.",
run->s.regs.diag318);
}
struct testdef {
const char *name;
void (*test)(struct kvm_vcpu *vcpu);
} testlist[] = {
{ "read invalid", test_read_invalid },
{ "set invalid", test_set_invalid },
{ "request+verify all valid regs", test_req_and_verify_all_valid_regs },
{ "set+verify various regs", test_set_and_verify_various_reg_values },
{ "clear kvm_dirty_regs bits", test_clear_kvm_dirty_regs_bits },
};
int main(int argc, char *argv[])
{
struct kvm_vcpu *vcpu;
struct kvm_vm *vm;
int idx;
TEST_REQUIRE(kvm_has_cap(KVM_CAP_SYNC_REGS));
ksft_print_header();
ksft_set_plan(ARRAY_SIZE(testlist));
/* Create VM */
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) {
testlist[idx].test(vcpu);
ksft_test_result_pass("%s\n", testlist[idx].name);
}
kvm_vm_free(vm);
ksft_finished(); /* Print results and exit() accordingly */
}