Skip to content

Commit 8e8678e

Browse files
committed
KVM: s390: Add capability that forwards operation exceptions
Setting KVM_CAP_S390_USER_OPEREXEC will forward all operation exceptions to user space. This also includes the 0x0000 instructions managed by KVM_CAP_S390_USER_INSTR0. It's helpful if user space wants to emulate instructions which do not (yet) have an opcode. While we're at it refine the documentation for KVM_CAP_S390_USER_INSTR0. Signed-off-by: Janosch Frank <frankja@linux.ibm.com> Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com> Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
1 parent 182a258 commit 8e8678e

7 files changed

Lines changed: 169 additions & 1 deletion

File tree

Documentation/virt/kvm/api.rst

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7820,7 +7820,7 @@ where 0xff represents CPUs 0-7 in cluster 0.
78207820
:Architectures: s390
78217821
:Parameters: none
78227822

7823-
With this capability enabled, all illegal instructions 0x0000 (2 bytes) will
7823+
With this capability enabled, the illegal instruction 0x0000 (2 bytes) will
78247824
be intercepted and forwarded to user space. User space can use this
78257825
mechanism e.g. to realize 2-byte software breakpoints. The kernel will
78267826
not inject an operating exception for these instructions, user space has
@@ -8703,6 +8703,21 @@ This capability indicate to the userspace whether a PFNMAP memory region
87038703
can be safely mapped as cacheable. This relies on the presence of
87048704
force write back (FWB) feature support on the hardware.
87058705

8706+
7.45 KVM_CAP_S390_USER_OPEREXEC
8707+
-------------------------------
8708+
8709+
:Architectures: s390
8710+
:Parameters: none
8711+
8712+
When this capability is enabled KVM forwards all operation exceptions
8713+
that it doesn't handle itself to user space. This also includes the
8714+
0x0000 instructions managed by KVM_CAP_S390_USER_INSTR0. This is
8715+
helpful if user space wants to emulate instructions which are not
8716+
(yet) implemented in hardware.
8717+
8718+
This capability can be enabled dynamically even if VCPUs were already
8719+
created and are running.
8720+
87068721
8. Other capabilities.
87078722
======================
87088723

arch/s390/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ struct kvm_arch {
648648
int user_sigp;
649649
int user_stsi;
650650
int user_instr0;
651+
int user_operexec;
651652
struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
652653
wait_queue_head_t ipte_wq;
653654
int ipte_lock_count;

arch/s390/kvm/intercept.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,9 @@ static int handle_operexc(struct kvm_vcpu *vcpu)
471471
if (vcpu->arch.sie_block->ipa == 0xb256)
472472
return handle_sthyi(vcpu);
473473

474+
if (vcpu->kvm->arch.user_operexec)
475+
return -EOPNOTSUPP;
476+
474477
if (vcpu->arch.sie_block->ipa == 0 && vcpu->kvm->arch.user_instr0)
475478
return -EOPNOTSUPP;
476479
rc = read_guest_lc(vcpu, __LC_PGM_NEW_PSW, &newpsw, sizeof(psw_t));

arch/s390/kvm/kvm-s390.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
606606
case KVM_CAP_SET_GUEST_DEBUG:
607607
case KVM_CAP_S390_DIAG318:
608608
case KVM_CAP_IRQFD_RESAMPLE:
609+
case KVM_CAP_S390_USER_OPEREXEC:
609610
r = 1;
610611
break;
611612
case KVM_CAP_SET_GUEST_DEBUG2:
@@ -921,6 +922,12 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
921922
VM_EVENT(kvm, 3, "ENABLE: CAP_S390_CPU_TOPOLOGY %s",
922923
r ? "(not available)" : "(success)");
923924
break;
925+
case KVM_CAP_S390_USER_OPEREXEC:
926+
VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_OPEREXEC");
927+
kvm->arch.user_operexec = 1;
928+
icpt_operexc_on_all_vcpus(kvm);
929+
r = 0;
930+
break;
924931
default:
925932
r = -EINVAL;
926933
break;

include/uapi/linux/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ struct kvm_enable_cap {
963963
#define KVM_CAP_RISCV_MP_STATE_RESET 242
964964
#define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243
965965
#define KVM_CAP_GUEST_MEMFD_FLAGS 244
966+
#define KVM_CAP_S390_USER_OPEREXEC 245
966967

967968
struct kvm_irq_routing_irqchip {
968969
__u32 irqchip;

tools/testing/selftests/kvm/Makefile.kvm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ TEST_GEN_PROGS_s390 += s390/debug_test
194194
TEST_GEN_PROGS_s390 += s390/cpumodel_subfuncs_test
195195
TEST_GEN_PROGS_s390 += s390/shared_zeropage_test
196196
TEST_GEN_PROGS_s390 += s390/ucontrol_test
197+
TEST_GEN_PROGS_s390 += s390/user_operexec
197198
TEST_GEN_PROGS_s390 += rseq_test
198199

199200
TEST_GEN_PROGS_riscv = $(TEST_GEN_PROGS_COMMON)
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* Test operation exception forwarding.
3+
*
4+
* Copyright IBM Corp. 2025
5+
*
6+
* Authors:
7+
* Janosch Frank <frankja@linux.ibm.com>
8+
*/
9+
#include "kselftest.h"
10+
#include "kvm_util.h"
11+
#include "test_util.h"
12+
#include "sie.h"
13+
14+
#include <linux/kvm.h>
15+
16+
static void guest_code_instr0(void)
17+
{
18+
asm(".word 0x0000");
19+
}
20+
21+
static void test_user_instr0(void)
22+
{
23+
struct kvm_vcpu *vcpu;
24+
struct kvm_vm *vm;
25+
int rc;
26+
27+
vm = vm_create_with_one_vcpu(&vcpu, guest_code_instr0);
28+
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0);
29+
TEST_ASSERT_EQ(0, rc);
30+
31+
vcpu_run(vcpu);
32+
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
33+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC);
34+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0);
35+
36+
kvm_vm_free(vm);
37+
}
38+
39+
static void guest_code_user_operexec(void)
40+
{
41+
asm(".word 0x0807");
42+
}
43+
44+
static void test_user_operexec(void)
45+
{
46+
struct kvm_vcpu *vcpu;
47+
struct kvm_vm *vm;
48+
int rc;
49+
50+
vm = vm_create_with_one_vcpu(&vcpu, guest_code_user_operexec);
51+
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0);
52+
TEST_ASSERT_EQ(0, rc);
53+
54+
vcpu_run(vcpu);
55+
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
56+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC);
57+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807);
58+
59+
kvm_vm_free(vm);
60+
61+
/*
62+
* Since user_operexec is the superset it can be used for the
63+
* 0 instruction.
64+
*/
65+
vm = vm_create_with_one_vcpu(&vcpu, guest_code_instr0);
66+
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0);
67+
TEST_ASSERT_EQ(0, rc);
68+
69+
vcpu_run(vcpu);
70+
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
71+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC);
72+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0);
73+
74+
kvm_vm_free(vm);
75+
}
76+
77+
/* combine user_instr0 and user_operexec */
78+
static void test_user_operexec_combined(void)
79+
{
80+
struct kvm_vcpu *vcpu;
81+
struct kvm_vm *vm;
82+
int rc;
83+
84+
vm = vm_create_with_one_vcpu(&vcpu, guest_code_user_operexec);
85+
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0);
86+
TEST_ASSERT_EQ(0, rc);
87+
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0);
88+
TEST_ASSERT_EQ(0, rc);
89+
90+
vcpu_run(vcpu);
91+
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
92+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC);
93+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807);
94+
95+
kvm_vm_free(vm);
96+
97+
/* Reverse enablement order */
98+
vm = vm_create_with_one_vcpu(&vcpu, guest_code_user_operexec);
99+
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0);
100+
TEST_ASSERT_EQ(0, rc);
101+
rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0);
102+
TEST_ASSERT_EQ(0, rc);
103+
104+
vcpu_run(vcpu);
105+
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
106+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC);
107+
TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807);
108+
109+
kvm_vm_free(vm);
110+
}
111+
112+
/*
113+
* Run all tests above.
114+
*
115+
* Enablement after VCPU has been added is automatically tested since
116+
* we enable the capability after VCPU creation.
117+
*/
118+
static struct testdef {
119+
const char *name;
120+
void (*test)(void);
121+
} testlist[] = {
122+
{ "instr0", test_user_instr0 },
123+
{ "operexec", test_user_operexec },
124+
{ "operexec_combined", test_user_operexec_combined},
125+
};
126+
127+
int main(int argc, char *argv[])
128+
{
129+
int idx;
130+
131+
TEST_REQUIRE(kvm_has_cap(KVM_CAP_S390_USER_INSTR0));
132+
133+
ksft_print_header();
134+
ksft_set_plan(ARRAY_SIZE(testlist));
135+
for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) {
136+
testlist[idx].test();
137+
ksft_test_result_pass("%s\n", testlist[idx].name);
138+
}
139+
ksft_finished();
140+
}

0 commit comments

Comments
 (0)