From 1a4794f17d0f279c55079717bc02d01ec9893eb3 Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Thu, 7 May 2026 22:08:35 +0200 Subject: KVM: s390: selftests: Extended user_operexec tests There is a possibility that the user_operexec capability only works if facility bit 74 is enabled. This is now fixed, but add a selftest to demonstrate that. Signed-off-by: Eric Farman Acked-by: Janosch Frank Reviewed-by: Claudio Imbrenda Signed-off-by: Claudio Imbrenda Message-ID: <20260507200836.3500368-3-farman@linux.ibm.com> --- .../testing/selftests/kvm/include/s390/facility.h | 6 ++ tools/testing/selftests/kvm/s390/user_operexec.c | 110 +++++++++++++++++++++ 2 files changed, 116 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/kvm/include/s390/facility.h b/tools/testing/selftests/kvm/include/s390/facility.h index 41a265742666..e5259f63be22 100644 --- a/tools/testing/selftests/kvm/include/s390/facility.h +++ b/tools/testing/selftests/kvm/include/s390/facility.h @@ -11,6 +11,7 @@ #ifndef SELFTEST_KVM_FACILITY_H #define SELFTEST_KVM_FACILITY_H +#include #include /* alt_stfle_fac_list[16] + stfle_fac_list[16] */ @@ -19,6 +20,11 @@ extern u64 stfl_doublewords[NB_STFL_DOUBLEWORDS]; extern bool stfle_flag; +static inline bool clear_bit_inv(unsigned long nr, unsigned long *ptr) +{ + return clear_bit(nr ^ (BITS_PER_LONG - 1), ptr); +} + static inline bool test_bit_inv(unsigned long nr, const unsigned long *ptr) { return test_bit(nr ^ (BITS_PER_LONG - 1), ptr); diff --git a/tools/testing/selftests/kvm/s390/user_operexec.c b/tools/testing/selftests/kvm/s390/user_operexec.c index 714906c1d12a..b24c1f9dbbe8 100644 --- a/tools/testing/selftests/kvm/s390/user_operexec.c +++ b/tools/testing/selftests/kvm/s390/user_operexec.c @@ -6,6 +6,7 @@ * Authors: * Janosch Frank */ +#include "facility.h" #include "kselftest.h" #include "kvm_util.h" #include "test_util.h" @@ -109,6 +110,111 @@ static void test_user_operexec_combined(void) kvm_vm_free(vm); } +static struct kvm_vm *create_vm_without_sthyi(void) +{ + struct kvm_s390_vm_cpu_processor info; + struct kvm_vm *vm; + + vm = vm_create(1); + + kvm_device_attr_get(vm->fd, KVM_S390_VM_CPU_MODEL, + KVM_S390_VM_CPU_PROCESSOR, &info); + + clear_bit_inv(74, (unsigned long *)&info.fac_list); + kvm_device_attr_set(vm->fd, KVM_S390_VM_CPU_MODEL, + KVM_S390_VM_CPU_PROCESSOR, &info); + + return vm; +} + +static void test_user_instr0_no_stfle_74(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int rc; + + vm = create_vm_without_sthyi(); + + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0); + TEST_ASSERT_EQ(0, rc); + + vcpu = vm_vcpu_add(vm, 0, guest_code_instr0); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0000); + + kvm_vm_free(vm); +} + +static void test_user_operexec_no_stfle_74(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int rc; + + vm = create_vm_without_sthyi(); + + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0); + TEST_ASSERT_EQ(0, rc); + + vcpu = vm_vcpu_add(vm, 0, guest_code_user_operexec); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807); + + kvm_vm_free(vm); +} + +static void test_instr0_combined_no_stfle_74(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int rc; + + vm = create_vm_without_sthyi(); + + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0); + TEST_ASSERT_EQ(0, rc); + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0); + TEST_ASSERT_EQ(0, rc); + + vcpu = vm_vcpu_add(vm, 0, guest_code_instr0); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0000); + + kvm_vm_free(vm); +} + +static void test_operexec_combined_no_stfle_74(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int rc; + + vm = create_vm_without_sthyi(); + + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0); + TEST_ASSERT_EQ(0, rc); + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0); + TEST_ASSERT_EQ(0, rc); + + vcpu = vm_vcpu_add(vm, 0, guest_code_user_operexec); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807); + + kvm_vm_free(vm); +} + /* * Run all tests above. * @@ -122,6 +228,10 @@ static struct testdef { { "instr0", test_user_instr0 }, { "operexec", test_user_operexec }, { "operexec_combined", test_user_operexec_combined}, + { "instr0_no_stfle_74", test_user_instr0_no_stfle_74 }, + { "instr0_combined_no_stfle_74", test_instr0_combined_no_stfle_74 }, + { "operexec_combined_no_stfle_74", test_operexec_combined_no_stfle_74 }, + { "operexec_no_stfle_74", test_user_operexec_no_stfle_74 }, }; int main(int argc, char *argv[]) -- cgit v1.2.3 From 125a3d3fac51571b8ede0d0599618c6ecd975ea8 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 23 Jun 2026 17:33:29 +0200 Subject: KVM: s390: selftests: Fix cmma selftest The existing cmma selftest depended on the host allocating page tables for all present memslots. Since the gmap rewrite, memory that is not accessed by the guest might not have page tables allocated yet. This caused the test to fail due to a mismatch in the assertion. Fix by having the guest access also the second half of the test memslot, thus guaranteeing that its page tables are present. Fixes: e38c884df921 ("KVM: s390: Switch to new gmap") Signed-off-by: Claudio Imbrenda Message-ID: <20260623153331.233784-9-imbrenda@linux.ibm.com> --- tools/testing/selftests/kvm/s390/cmma_test.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/kvm/s390/cmma_test.c b/tools/testing/selftests/kvm/s390/cmma_test.c index e39a724fe860..15d81b2ed7ad 100644 --- a/tools/testing/selftests/kvm/s390/cmma_test.c +++ b/tools/testing/selftests/kvm/s390/cmma_test.c @@ -34,16 +34,22 @@ static char cmma_value_buf[MAIN_PAGE_COUNT + TEST_DATA_PAGE_COUNT]; /** * Dirty CMMA attributes of exactly one page in the TEST_DATA memslot, * so use_cmma goes on and the CMMA related ioctls do something. + * Touch the page at offset 1M inside TEST_DATA to make sure its page + * tables are allocated in the host. */ static void guest_do_one_essa(void) { asm volatile( /* load TEST_DATA_START_GFN into r1 */ + " xgr 1,1\n" " llilf 1,%[start_gfn]\n" /* calculate the address from the gfn */ " sllg 1,1,12(0)\n" /* set the first page in TEST_DATA memslot to STABLE */ " .insn rrf,0xb9ab0000,2,1,1,0\n" + " agfi 1,0x100000\n" + /* also touch the first page of the second MB of TEST_DATA */ + " .insn rrf,0xb9ab0000,2,1,1,0\n" /* hypercall */ " diag 0,0,0x501\n" "0: j 0b" -- cgit v1.2.3