2023-07-25 15:01:20

by Ilya Leoshkevich

[permalink] [raw]
Subject: [PATCH v4 0/6] KVM: s390: interrupt: Fix stepping into interrupt handlers

v3: https://lore.kernel.org/kvm/[email protected]/
v3 -> v4: Restore the per_event() macro (Claudio).

v2: https://lore.kernel.org/lkml/[email protected]/
v2 -> v3: Add comments, improve the commit messages (Christian, David).
Add R-bs.
Patches that need review: [4/6], [6/6].

v1: https://lore.kernel.org/lkml/[email protected]/
v1 -> v2: Fix three more issues.
Add selftests (Claudio).

Hi,

I tried to compare the behavior of KVM and TCG by diffing instruction
traces, and found five issues in KVM related to stepping into interrupt
handlers.

Best regards,
Ilya

Ilya Leoshkevich (6):
KVM: s390: interrupt: Fix single-stepping into interrupt handlers
KVM: s390: interrupt: Fix single-stepping into program interrupt
handlers
KVM: s390: interrupt: Fix single-stepping kernel-emulated instructions
KVM: s390: interrupt: Fix single-stepping userspace-emulated
instructions
KVM: s390: interrupt: Fix single-stepping keyless mode exits
KVM: s390: selftests: Add selftest for single-stepping

arch/s390/kvm/intercept.c | 38 ++++-
arch/s390/kvm/interrupt.c | 14 ++
arch/s390/kvm/kvm-s390.c | 27 ++-
tools/testing/selftests/kvm/Makefile | 1 +
.../testing/selftests/kvm/s390x/debug_test.c | 160 ++++++++++++++++++
5 files changed, 229 insertions(+), 11 deletions(-)
create mode 100644 tools/testing/selftests/kvm/s390x/debug_test.c

--
2.41.0



2023-07-25 15:01:48

by Ilya Leoshkevich

[permalink] [raw]
Subject: [PATCH v4 6/6] KVM: s390: selftests: Add selftest for single-stepping

Test different variations of single-stepping into interrupts:

- SVC and PGM interrupts;
- Interrupts generated by ISKE;
- Interrupts generated by instructions emulated by KVM;
- Interrupts generated by instructions emulated by userspace.

Reviewed-by: Claudio Imbrenda <[email protected]>
Signed-off-by: Ilya Leoshkevich <[email protected]>
---
tools/testing/selftests/kvm/Makefile | 1 +
.../testing/selftests/kvm/s390x/debug_test.c | 160 ++++++++++++++++++
2 files changed, 161 insertions(+)
create mode 100644 tools/testing/selftests/kvm/s390x/debug_test.c

diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index c692cc86e7da..f3306eaa7031 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -166,6 +166,7 @@ TEST_GEN_PROGS_s390x += s390x/resets
TEST_GEN_PROGS_s390x += s390x/sync_regs_test
TEST_GEN_PROGS_s390x += s390x/tprot
TEST_GEN_PROGS_s390x += s390x/cmma_test
+TEST_GEN_PROGS_s390x += s390x/debug_test
TEST_GEN_PROGS_s390x += demand_paging_test
TEST_GEN_PROGS_s390x += dirty_log_test
TEST_GEN_PROGS_s390x += kvm_create_max_vcpus
diff --git a/tools/testing/selftests/kvm/s390x/debug_test.c b/tools/testing/selftests/kvm/s390x/debug_test.c
new file mode 100644
index 000000000000..a8fa9fe93b3c
--- /dev/null
+++ b/tools/testing/selftests/kvm/s390x/debug_test.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Test KVM debugging features. */
+#include "kvm_util.h"
+#include "test_util.h"
+
+#include <linux/kvm.h>
+
+#define __LC_SVC_NEW_PSW 0x1c0
+#define __LC_PGM_NEW_PSW 0x1d0
+#define ICPT_INSTRUCTION 0x04
+#define IPA0_DIAG 0x8300
+#define PGM_SPECIFICATION 0x06
+
+/* Common code for testing single-stepping interruptions. */
+extern char int_handler[];
+asm("int_handler:\n"
+ "j .\n");
+
+static struct kvm_vm *test_step_int_1(struct kvm_vcpu **vcpu, void *guest_code,
+ size_t new_psw_off, uint64_t *new_psw)
+{
+ struct kvm_guest_debug debug = {};
+ struct kvm_regs regs;
+ struct kvm_vm *vm;
+ char *lowcore;
+
+ vm = vm_create_with_one_vcpu(vcpu, guest_code);
+ lowcore = addr_gpa2hva(vm, 0);
+ new_psw[0] = (*vcpu)->run->psw_mask;
+ new_psw[1] = (uint64_t)int_handler;
+ memcpy(lowcore + new_psw_off, new_psw, 16);
+ vcpu_regs_get(*vcpu, &regs);
+ regs.gprs[2] = -1;
+ vcpu_regs_set(*vcpu, &regs);
+ debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
+ vcpu_guest_debug_set(*vcpu, &debug);
+ vcpu_run(*vcpu);
+
+ return vm;
+}
+
+static void test_step_int(void *guest_code, size_t new_psw_off)
+{
+ struct kvm_vcpu *vcpu;
+ uint64_t new_psw[2];
+ struct kvm_vm *vm;
+
+ vm = test_step_int_1(&vcpu, guest_code, new_psw_off, new_psw);
+ TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_DEBUG);
+ ASSERT_EQ(vcpu->run->psw_mask, new_psw[0]);
+ ASSERT_EQ(vcpu->run->psw_addr, new_psw[1]);
+ kvm_vm_free(vm);
+}
+
+/* Test single-stepping "boring" program interruptions. */
+extern char test_step_pgm_guest_code[];
+asm("test_step_pgm_guest_code:\n"
+ ".insn rr,0x1d00,%r1,%r0 /* dr %r1,%r0 */\n"
+ "j .\n");
+
+static void test_step_pgm(void)
+{
+ test_step_int(test_step_pgm_guest_code, __LC_PGM_NEW_PSW);
+}
+
+/*
+ * Test single-stepping program interruptions caused by DIAG.
+ * Userspace emulation must not interfere with single-stepping.
+ */
+extern char test_step_pgm_diag_guest_code[];
+asm("test_step_pgm_diag_guest_code:\n"
+ "diag %r0,%r0,0\n"
+ "j .\n");
+
+static void test_step_pgm_diag(void)
+{
+ struct kvm_s390_irq irq = {
+ .type = KVM_S390_PROGRAM_INT,
+ .u.pgm.code = PGM_SPECIFICATION,
+ };
+ struct kvm_vcpu *vcpu;
+ uint64_t new_psw[2];
+ struct kvm_vm *vm;
+
+ vm = test_step_int_1(&vcpu, test_step_pgm_diag_guest_code,
+ __LC_PGM_NEW_PSW, new_psw);
+ TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);
+ ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_INSTRUCTION);
+ ASSERT_EQ(vcpu->run->s390_sieic.ipa & 0xff00, IPA0_DIAG);
+ vcpu_ioctl(vcpu, KVM_S390_IRQ, &irq);
+ vcpu_run(vcpu);
+ TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_DEBUG);
+ ASSERT_EQ(vcpu->run->psw_mask, new_psw[0]);
+ ASSERT_EQ(vcpu->run->psw_addr, new_psw[1]);
+ kvm_vm_free(vm);
+}
+
+/*
+ * Test single-stepping program interruptions caused by ISKE.
+ * CPUSTAT_KSS handling must not interfere with single-stepping.
+ */
+extern char test_step_pgm_iske_guest_code[];
+asm("test_step_pgm_iske_guest_code:\n"
+ "iske %r2,%r2\n"
+ "j .\n");
+
+static void test_step_pgm_iske(void)
+{
+ test_step_int(test_step_pgm_iske_guest_code, __LC_PGM_NEW_PSW);
+}
+
+/*
+ * Test single-stepping program interruptions caused by LCTL.
+ * KVM emulation must not interfere with single-stepping.
+ */
+extern char test_step_pgm_lctl_guest_code[];
+asm("test_step_pgm_lctl_guest_code:\n"
+ "lctl %c0,%c0,1\n"
+ "j .\n");
+
+static void test_step_pgm_lctl(void)
+{
+ test_step_int(test_step_pgm_lctl_guest_code, __LC_PGM_NEW_PSW);
+}
+
+/* Test single-stepping supervisor-call interruptions. */
+extern char test_step_svc_guest_code[];
+asm("test_step_svc_guest_code:\n"
+ "svc 0\n"
+ "j .\n");
+
+static void test_step_svc(void)
+{
+ test_step_int(test_step_svc_guest_code, __LC_SVC_NEW_PSW);
+}
+
+/* Run all tests above. */
+static struct testdef {
+ const char *name;
+ void (*test)(void);
+} testlist[] = {
+ { "single-step pgm", test_step_pgm },
+ { "single-step pgm caused by diag", test_step_pgm_diag },
+ { "single-step pgm caused by iske", test_step_pgm_iske },
+ { "single-step pgm caused by lctl", test_step_pgm_lctl },
+ { "single-step svc", test_step_svc },
+};
+
+int main(int argc, char *argv[])
+{
+ int idx;
+
+ ksft_print_header();
+ ksft_set_plan(ARRAY_SIZE(testlist));
+ for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) {
+ testlist[idx].test();
+ ksft_test_result_pass("%s\n", testlist[idx].name);
+ }
+ ksft_finished();
+}
--
2.41.0


2023-07-25 15:17:05

by Ilya Leoshkevich

[permalink] [raw]
Subject: [PATCH v4 5/6] KVM: s390: interrupt: Fix single-stepping keyless mode exits

kvm_s390_skey_check_enable() does not emulate any instructions, rather,
it clears CPUSTAT_KSS and arranges the instruction that caused the exit
(e.g., ISKE, SSKE, RRBE or LPSWE with a keyed PSW) to run again.

Therefore, skip the PER check and let the instruction execution happen.
Otherwise, a debugger will see two single-step events on the same
instruction.

Reviewed-by: Christian Borntraeger <[email protected]>
Reviewed-by: David Hildenbrand <[email protected]>
Signed-off-by: Ilya Leoshkevich <[email protected]>
---
arch/s390/kvm/intercept.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index db222c749e5e..9f64f27f086e 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -630,8 +630,8 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
rc = handle_partial_execution(vcpu);
break;
case ICPT_KSS:
- rc = kvm_s390_skey_check_enable(vcpu);
- break;
+ /* Instruction will be redriven, skip the PER check. */
+ return kvm_s390_skey_check_enable(vcpu);
case ICPT_MCHKREQ:
case ICPT_INT_ENABLE:
/*
--
2.41.0


2023-07-25 16:15:22

by Ilya Leoshkevich

[permalink] [raw]
Subject: [PATCH v4 2/6] KVM: s390: interrupt: Fix single-stepping into program interrupt handlers

Currently, after single-stepping an instruction that generates a
specification exception, GDB ends up on the instruction immediately
following it.

The reason is that vcpu_post_run() injects the interrupt and sets
KVM_GUESTDBG_EXIT_PENDING, causing a KVM_SINGLESTEP exit. The
interrupt is not delivered, however, therefore userspace sees the
address of the next instruction.

Fix by letting the __vcpu_run() loop go into the next iteration,
where vcpu_pre_run() delivers the interrupt and sets
KVM_GUESTDBG_EXIT_PENDING.

Reviewed-by: David Hildenbrand <[email protected]>
Signed-off-by: Ilya Leoshkevich <[email protected]>
---
arch/s390/kvm/intercept.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 954d39adf85c..e54496740859 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -228,6 +228,21 @@ static int handle_itdb(struct kvm_vcpu *vcpu)

#define per_event(vcpu) (vcpu->arch.sie_block->iprcc & PGM_PER)

+static bool should_handle_per_event(const struct kvm_vcpu *vcpu)
+{
+ if (!guestdbg_enabled(vcpu) || !per_event(vcpu))
+ return false;
+ if (guestdbg_sstep_enabled(vcpu) &&
+ vcpu->arch.sie_block->iprcc != PGM_PER) {
+ /*
+ * __vcpu_run() will exit after delivering the concurrently
+ * indicated condition.
+ */
+ return false;
+ }
+ return true;
+}
+
static int handle_prog(struct kvm_vcpu *vcpu)
{
psw_t psw;
@@ -242,7 +257,7 @@ static int handle_prog(struct kvm_vcpu *vcpu)
if (kvm_s390_pv_cpu_is_protected(vcpu))
return -EOPNOTSUPP;

- if (guestdbg_enabled(vcpu) && per_event(vcpu)) {
+ if (should_handle_per_event(vcpu)) {
rc = kvm_s390_handle_per_event(vcpu);
if (rc)
return rc;
--
2.41.0


2023-08-03 00:06:36

by Sean Christopherson

[permalink] [raw]
Subject: Re: [PATCH v4 0/6] KVM: s390: interrupt: Fix stepping into interrupt handlers

On Tue, Jul 25, 2023, Ilya Leoshkevich wrote:
> Ilya Leoshkevich (6):
> KVM: s390: interrupt: Fix single-stepping into interrupt handlers
> KVM: s390: interrupt: Fix single-stepping into program interrupt
> handlers
> KVM: s390: interrupt: Fix single-stepping kernel-emulated instructions
> KVM: s390: interrupt: Fix single-stepping userspace-emulated
> instructions
> KVM: s390: interrupt: Fix single-stepping keyless mode exits
> KVM: s390: selftests: Add selftest for single-stepping

FYI, the selftests change silently conflicts with a global s/ASSERT_EQ/TEST_ASSERT_EQ
rename[1], but the conflicts are very straightforward to resolve (just prepend TEST_).
If we want to proactively avoid mild pain in linux-next, one option would be to merge
the full kvm-x86/selftests branch/tag once I've made that immutable[2] (will be done
Friday if there are no fireworks). Though we can probably just get away with doing
nothing other than letting Paolo know there's a silent conflict.

[1] https://lore.kernel.org/all/[email protected]
[2] https://lore.kernel.org/all/[email protected]


2023-08-03 08:17:45

by Christian Borntraeger

[permalink] [raw]
Subject: Re: [PATCH v4 0/6] KVM: s390: interrupt: Fix stepping into interrupt handlers



Am 03.08.23 um 00:24 schrieb Sean Christopherson:
> On Tue, Jul 25, 2023, Ilya Leoshkevich wrote:
>> Ilya Leoshkevich (6):
>> KVM: s390: interrupt: Fix single-stepping into interrupt handlers
>> KVM: s390: interrupt: Fix single-stepping into program interrupt
>> handlers
>> KVM: s390: interrupt: Fix single-stepping kernel-emulated instructions
>> KVM: s390: interrupt: Fix single-stepping userspace-emulated
>> instructions
>> KVM: s390: interrupt: Fix single-stepping keyless mode exits
>> KVM: s390: selftests: Add selftest for single-stepping
>
> FYI, the selftests change silently conflicts with a global s/ASSERT_EQ/TEST_ASSERT_EQ
> rename[1], but the conflicts are very straightforward to resolve (just prepend TEST_).
> If we want to proactively avoid mild pain in linux-next, one option would be to merge
> the full kvm-x86/selftests branch/tag once I've made that immutable[2] (will be done
> Friday if there are no fireworks). Though we can probably just get away with doing
> nothing other than letting Paolo know there's a silent conflict.
>
> [1] https://lore.kernel.org/all/[email protected]
> [2] https://lore.kernel.org/all/[email protected]

Thanks for telling. Paolo, do you have a preference?

Janosch, Claudio I think this series is good to go otherwise.