xref: /kvm-unit-tests/s390x/sie.c (revision d1e2a8e2d0d5856f1a6ce23ea3f044a1532eab40)
1aa8794b1SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
2aa8794b1SJanosch Frank /*
3aa8794b1SJanosch Frank  * Tests SIE diagnose intercepts.
4aa8794b1SJanosch Frank  * Mainly used as a template for SIE tests.
5aa8794b1SJanosch Frank  *
6aa8794b1SJanosch Frank  * Copyright 2021 IBM Corp.
7aa8794b1SJanosch Frank  *
8aa8794b1SJanosch Frank  * Authors:
9aa8794b1SJanosch Frank  *    Janosch Frank <frankja@linux.ibm.com>
10aa8794b1SJanosch Frank  */
119ec666ecSJanosch Frank #include <libcflat.h>
129ec666ecSJanosch Frank #include <asm/asm-offsets.h>
139ec666ecSJanosch Frank #include <asm/arch_def.h>
149ec666ecSJanosch Frank #include <asm/interrupt.h>
159ec666ecSJanosch Frank #include <asm/page.h>
169ec666ecSJanosch Frank #include <alloc_page.h>
179ec666ecSJanosch Frank #include <vmalloc.h>
189ec666ecSJanosch Frank #include <asm/facility.h>
199ec666ecSJanosch Frank #include <mmu.h>
209ec666ecSJanosch Frank #include <sclp.h>
219ec666ecSJanosch Frank #include <sie.h>
229ec666ecSJanosch Frank 
239ec666ecSJanosch Frank static u8 *guest;
249ec666ecSJanosch Frank static u8 *guest_instr;
259ec666ecSJanosch Frank static struct vm vm;
269ec666ecSJanosch Frank 
test_diag(u32 instr)279ec666ecSJanosch Frank static void test_diag(u32 instr)
289ec666ecSJanosch Frank {
299ec666ecSJanosch Frank 	vm.sblk->gpsw.addr = PAGE_SIZE * 2;
3044026818SJanosch Frank 	vm.sblk->gpsw.mask = PSW_MASK_64;
319ec666ecSJanosch Frank 
329ec666ecSJanosch Frank 	memset(guest_instr, 0, PAGE_SIZE);
339ec666ecSJanosch Frank 	memcpy(guest_instr, &instr, 4);
349ec666ecSJanosch Frank 	sie(&vm);
359ec666ecSJanosch Frank 	report(vm.sblk->icptcode == ICPT_INST &&
369ec666ecSJanosch Frank 	       vm.sblk->ipa == instr >> 16 && vm.sblk->ipb == instr << 16,
379ec666ecSJanosch Frank 	       "Intercept data");
389ec666ecSJanosch Frank }
399ec666ecSJanosch Frank 
409ec666ecSJanosch Frank static struct {
419ec666ecSJanosch Frank 	const char *name;
429ec666ecSJanosch Frank 	u32 instr;
439ec666ecSJanosch Frank } tests[] = {
449ec666ecSJanosch Frank 	{ "10", 0x83020010 },
459ec666ecSJanosch Frank 	{ "44", 0x83020044 },
469ec666ecSJanosch Frank 	{ "9c", 0x8302009c },
479ec666ecSJanosch Frank 	{ NULL, 0 }
489ec666ecSJanosch Frank };
499ec666ecSJanosch Frank 
test_diags(void)509ec666ecSJanosch Frank static void test_diags(void)
519ec666ecSJanosch Frank {
529ec666ecSJanosch Frank 	int i;
539ec666ecSJanosch Frank 
549ec666ecSJanosch Frank 	for (i = 0; tests[i].name; i++) {
559ec666ecSJanosch Frank 		report_prefix_push(tests[i].name);
569ec666ecSJanosch Frank 		test_diag(tests[i].instr);
579ec666ecSJanosch Frank 		report_prefix_pop();
589ec666ecSJanosch Frank 	}
599ec666ecSJanosch Frank }
609ec666ecSJanosch Frank 
test_epoch_ext(void)61f72ecf78SThomas Huth static void test_epoch_ext(void)
62f72ecf78SThomas Huth {
63f72ecf78SThomas Huth 	u32 instr[] = {
64f72ecf78SThomas Huth 		0xb2780000,	/* STCKE 0 */
65f72ecf78SThomas Huth 		0x83000044	/* DIAG 0x44 to intercept */
66f72ecf78SThomas Huth 	};
67f72ecf78SThomas Huth 
68f72ecf78SThomas Huth 	if (!test_facility(139)) {
69f72ecf78SThomas Huth 		report_skip("epdx: Multiple Epoch Facility is not available");
70f72ecf78SThomas Huth 		return;
71f72ecf78SThomas Huth 	}
72f72ecf78SThomas Huth 
73f72ecf78SThomas Huth 	guest[0] = 0x00;
74f72ecf78SThomas Huth 	memcpy(guest_instr, instr, sizeof(instr));
75f72ecf78SThomas Huth 
76f72ecf78SThomas Huth 	vm.sblk->gpsw.addr = PAGE_SIZE * 2;
77f72ecf78SThomas Huth 	vm.sblk->gpsw.mask = PSW_MASK_64;
78f72ecf78SThomas Huth 
79f72ecf78SThomas Huth 	vm.sblk->ecd |= ECD_MEF;
80f72ecf78SThomas Huth 	vm.sblk->epdx = 0x47;	/* Setting the epoch extension here ... */
81f72ecf78SThomas Huth 
82f72ecf78SThomas Huth 	sie(&vm);
83f72ecf78SThomas Huth 
84f72ecf78SThomas Huth 	/* ... should result in the same epoch extension here: */
85f72ecf78SThomas Huth 	report(guest[0] == 0x47, "epdx: different epoch is visible in the guest");
86f72ecf78SThomas Huth }
87f72ecf78SThomas Huth 
setup_guest(void)889ec666ecSJanosch Frank static void setup_guest(void)
899ec666ecSJanosch Frank {
909ec666ecSJanosch Frank 	setup_vm();
919ec666ecSJanosch Frank 
92*ae337a39SNico Boehr 	guest = sie_guest_alloc(SZ_1M);
93*ae337a39SNico Boehr 
949ec666ecSJanosch Frank 	/* The first two pages are the lowcore */
959ec666ecSJanosch Frank 	guest_instr = guest + PAGE_SIZE * 2;
969ec666ecSJanosch Frank 
97a58e5546SJanosch Frank 	sie_guest_create(&vm, (uint64_t)guest, HPAGE_SIZE);
989ec666ecSJanosch Frank }
999ec666ecSJanosch Frank 
main(void)1009ec666ecSJanosch Frank int main(void)
1019ec666ecSJanosch Frank {
1029ec666ecSJanosch Frank 	report_prefix_push("sie");
1039ec666ecSJanosch Frank 	if (!sclp_facilities.has_sief2) {
1049ec666ecSJanosch Frank 		report_skip("SIEF2 facility unavailable");
1059ec666ecSJanosch Frank 		goto done;
1069ec666ecSJanosch Frank 	}
1079ec666ecSJanosch Frank 
1089ec666ecSJanosch Frank 	setup_guest();
1099ec666ecSJanosch Frank 	test_diags();
110f72ecf78SThomas Huth 	test_epoch_ext();
111a58e5546SJanosch Frank 	sie_guest_destroy(&vm);
112a58e5546SJanosch Frank 
1139ec666ecSJanosch Frank done:
1149ec666ecSJanosch Frank 	report_prefix_pop();
1159ec666ecSJanosch Frank 	return report_summary();
1169ec666ecSJanosch Frank }
117