xref: /kvm-unit-tests/s390x/sie.c (revision d1e2a8e2d0d5856f1a6ce23ea3f044a1532eab40)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Tests SIE diagnose intercepts.
4  * Mainly used as a template for SIE tests.
5  *
6  * Copyright 2021 IBM Corp.
7  *
8  * Authors:
9  *    Janosch Frank <frankja@linux.ibm.com>
10  */
11 #include <libcflat.h>
12 #include <asm/asm-offsets.h>
13 #include <asm/arch_def.h>
14 #include <asm/interrupt.h>
15 #include <asm/page.h>
16 #include <alloc_page.h>
17 #include <vmalloc.h>
18 #include <asm/facility.h>
19 #include <mmu.h>
20 #include <sclp.h>
21 #include <sie.h>
22 
23 static u8 *guest;
24 static u8 *guest_instr;
25 static struct vm vm;
26 
test_diag(u32 instr)27 static void test_diag(u32 instr)
28 {
29 	vm.sblk->gpsw.addr = PAGE_SIZE * 2;
30 	vm.sblk->gpsw.mask = PSW_MASK_64;
31 
32 	memset(guest_instr, 0, PAGE_SIZE);
33 	memcpy(guest_instr, &instr, 4);
34 	sie(&vm);
35 	report(vm.sblk->icptcode == ICPT_INST &&
36 	       vm.sblk->ipa == instr >> 16 && vm.sblk->ipb == instr << 16,
37 	       "Intercept data");
38 }
39 
40 static struct {
41 	const char *name;
42 	u32 instr;
43 } tests[] = {
44 	{ "10", 0x83020010 },
45 	{ "44", 0x83020044 },
46 	{ "9c", 0x8302009c },
47 	{ NULL, 0 }
48 };
49 
test_diags(void)50 static void test_diags(void)
51 {
52 	int i;
53 
54 	for (i = 0; tests[i].name; i++) {
55 		report_prefix_push(tests[i].name);
56 		test_diag(tests[i].instr);
57 		report_prefix_pop();
58 	}
59 }
60 
test_epoch_ext(void)61 static void test_epoch_ext(void)
62 {
63 	u32 instr[] = {
64 		0xb2780000,	/* STCKE 0 */
65 		0x83000044	/* DIAG 0x44 to intercept */
66 	};
67 
68 	if (!test_facility(139)) {
69 		report_skip("epdx: Multiple Epoch Facility is not available");
70 		return;
71 	}
72 
73 	guest[0] = 0x00;
74 	memcpy(guest_instr, instr, sizeof(instr));
75 
76 	vm.sblk->gpsw.addr = PAGE_SIZE * 2;
77 	vm.sblk->gpsw.mask = PSW_MASK_64;
78 
79 	vm.sblk->ecd |= ECD_MEF;
80 	vm.sblk->epdx = 0x47;	/* Setting the epoch extension here ... */
81 
82 	sie(&vm);
83 
84 	/* ... should result in the same epoch extension here: */
85 	report(guest[0] == 0x47, "epdx: different epoch is visible in the guest");
86 }
87 
setup_guest(void)88 static void setup_guest(void)
89 {
90 	setup_vm();
91 
92 	guest = sie_guest_alloc(SZ_1M);
93 
94 	/* The first two pages are the lowcore */
95 	guest_instr = guest + PAGE_SIZE * 2;
96 
97 	sie_guest_create(&vm, (uint64_t)guest, HPAGE_SIZE);
98 }
99 
main(void)100 int main(void)
101 {
102 	report_prefix_push("sie");
103 	if (!sclp_facilities.has_sief2) {
104 		report_skip("SIEF2 facility unavailable");
105 		goto done;
106 	}
107 
108 	setup_guest();
109 	test_diags();
110 	test_epoch_ext();
111 	sie_guest_destroy(&vm);
112 
113 done:
114 	report_prefix_pop();
115 	return report_summary();
116 }
117