Path: blob/master/tools/testing/selftests/kvm/s390/debug_test.c
38237 views
// SPDX-License-Identifier: GPL-2.0-only1/* Test KVM debugging features. */2#include "kvm_util.h"3#include "test_util.h"4#include "sie.h"56#include <linux/kvm.h>78#define __LC_SVC_NEW_PSW 0x1c09#define __LC_PGM_NEW_PSW 0x1d010#define IPA0_DIAG 0x830011#define PGM_SPECIFICATION 0x061213/* Common code for testing single-stepping interruptions. */14extern char int_handler[];15asm("int_handler:\n"16"j .\n");1718static struct kvm_vm *test_step_int_1(struct kvm_vcpu **vcpu, void *guest_code,19size_t new_psw_off, uint64_t *new_psw)20{21struct kvm_guest_debug debug = {};22struct kvm_regs regs;23struct kvm_vm *vm;24char *lowcore;2526vm = vm_create_with_one_vcpu(vcpu, guest_code);27lowcore = addr_gpa2hva(vm, 0);28new_psw[0] = (*vcpu)->run->psw_mask;29new_psw[1] = (uint64_t)int_handler;30memcpy(lowcore + new_psw_off, new_psw, 16);31vcpu_regs_get(*vcpu, ®s);32regs.gprs[2] = -1;33vcpu_regs_set(*vcpu, ®s);34debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;35vcpu_guest_debug_set(*vcpu, &debug);36vcpu_run(*vcpu);3738return vm;39}4041static void test_step_int(void *guest_code, size_t new_psw_off)42{43struct kvm_vcpu *vcpu;44uint64_t new_psw[2];45struct kvm_vm *vm;4647vm = test_step_int_1(&vcpu, guest_code, new_psw_off, new_psw);48TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_DEBUG);49TEST_ASSERT_EQ(vcpu->run->psw_mask, new_psw[0]);50TEST_ASSERT_EQ(vcpu->run->psw_addr, new_psw[1]);51kvm_vm_free(vm);52}5354/* Test single-stepping "boring" program interruptions. */55extern char test_step_pgm_guest_code[];56asm("test_step_pgm_guest_code:\n"57".insn rr,0x1d00,%r1,%r0 /* dr %r1,%r0 */\n"58"j .\n");5960static void test_step_pgm(void)61{62test_step_int(test_step_pgm_guest_code, __LC_PGM_NEW_PSW);63}6465/*66* Test single-stepping program interruptions caused by DIAG.67* Userspace emulation must not interfere with single-stepping.68*/69extern char test_step_pgm_diag_guest_code[];70asm("test_step_pgm_diag_guest_code:\n"71"diag %r0,%r0,0\n"72"j .\n");7374static void test_step_pgm_diag(void)75{76struct kvm_s390_irq irq = {77.type = KVM_S390_PROGRAM_INT,78.u.pgm.code = PGM_SPECIFICATION,79};80struct kvm_vcpu *vcpu;81uint64_t new_psw[2];82struct kvm_vm *vm;8384vm = test_step_int_1(&vcpu, test_step_pgm_diag_guest_code,85__LC_PGM_NEW_PSW, new_psw);86TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC);87TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_INST);88TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa & 0xff00, IPA0_DIAG);89vcpu_ioctl(vcpu, KVM_S390_IRQ, &irq);90vcpu_run(vcpu);91TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_DEBUG);92TEST_ASSERT_EQ(vcpu->run->psw_mask, new_psw[0]);93TEST_ASSERT_EQ(vcpu->run->psw_addr, new_psw[1]);94kvm_vm_free(vm);95}9697/*98* Test single-stepping program interruptions caused by ISKE.99* CPUSTAT_KSS handling must not interfere with single-stepping.100*/101extern char test_step_pgm_iske_guest_code[];102asm("test_step_pgm_iske_guest_code:\n"103"iske %r2,%r2\n"104"j .\n");105106static void test_step_pgm_iske(void)107{108test_step_int(test_step_pgm_iske_guest_code, __LC_PGM_NEW_PSW);109}110111/*112* Test single-stepping program interruptions caused by LCTL.113* KVM emulation must not interfere with single-stepping.114*/115extern char test_step_pgm_lctl_guest_code[];116asm("test_step_pgm_lctl_guest_code:\n"117"lctl %c0,%c0,1\n"118"j .\n");119120static void test_step_pgm_lctl(void)121{122test_step_int(test_step_pgm_lctl_guest_code, __LC_PGM_NEW_PSW);123}124125/* Test single-stepping supervisor-call interruptions. */126extern char test_step_svc_guest_code[];127asm("test_step_svc_guest_code:\n"128"svc 0\n"129"j .\n");130131static void test_step_svc(void)132{133test_step_int(test_step_svc_guest_code, __LC_SVC_NEW_PSW);134}135136/* Run all tests above. */137static struct testdef {138const char *name;139void (*test)(void);140} testlist[] = {141{ "single-step pgm", test_step_pgm },142{ "single-step pgm caused by diag", test_step_pgm_diag },143{ "single-step pgm caused by iske", test_step_pgm_iske },144{ "single-step pgm caused by lctl", test_step_pgm_lctl },145{ "single-step svc", test_step_svc },146};147148int main(int argc, char *argv[])149{150int idx;151152ksft_print_header();153ksft_set_plan(ARRAY_SIZE(testlist));154for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) {155testlist[idx].test();156ksft_test_result_pass("%s\n", testlist[idx].name);157}158ksft_finished();159}160161162