xref: /kvm-unit-tests/s390x/skey.c (revision 6163f75d09a0a96a5c3db82dd768b13f79629c00)
1 /*
2  * Storage key tests
3  *
4  * Copyright (c) 2018 IBM Corp
5  *
6  * Authors:
7  *  Janosch Frank <frankja@linux.vnet.ibm.com>
8  *
9  * This code is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Library General Public License version 2.
11  */
12 #include <libcflat.h>
13 #include <asm/asm-offsets.h>
14 #include <asm/interrupt.h>
15 #include <asm/page.h>
16 #include <asm/facility.h>
17 #include <asm/mem.h>
18 
19 
20 static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
21 
22 static void test_set_mb(void)
23 {
24 	union skey skey, ret1, ret2;
25 	void *addr = (void *)0x10000 - 2 * PAGE_SIZE;
26 	void *end = (void *)0x10000;
27 
28 	/* Multi block support came with EDAT 1 */
29 	if (!test_facility(8))
30 		return;
31 
32 	skey.val = 0x30;
33 	while (addr < end)
34 		addr = set_storage_key_mb(addr, skey.val);
35 
36 	ret1.val = get_storage_key(end - PAGE_SIZE) & (SKEY_ACC | SKEY_FP);
37 	ret2.val = get_storage_key(end - PAGE_SIZE * 2) & (SKEY_ACC | SKEY_FP);
38 	report("multi block",
39 	       ret1.val == ret2.val && ret1.val == skey.val);
40 }
41 
42 static void test_chg(void)
43 {
44 	union skey skey1, skey2;
45 
46 	skey1.val = 0x30;
47 	set_storage_key(pagebuf, skey1.val, 0);
48 	skey1.val = get_storage_key(pagebuf);
49 	pagebuf[0] = 3;
50 	skey2.val = get_storage_key(pagebuf);
51 	report("chg bit test", !skey1.str.ch && skey2.str.ch);
52 }
53 
54 static void test_set(void)
55 {
56 	union skey skey, ret;
57 
58 	skey.val = 0x30;
59 	ret.val = get_storage_key(pagebuf);
60 	set_storage_key(pagebuf, skey.val, 0);
61 	ret.val = get_storage_key(pagebuf);
62 	/*
63 	 * For all set tests we only test the ACC and FP bits. RF and
64 	 * CH are set by the machine for memory references and changes
65 	 * and hence might change between a set and a get.
66 	 */
67 	report("set key test",
68 	       skey.str.acc == ret.str.acc && skey.str.fp == ret.str.fp);
69 }
70 
71 /* Returns true if we are running under z/VM 6.x */
72 static bool check_for_zvm6(void)
73 {
74 	int dcbt;	/* Descriptor block count */
75 	int nr;
76 	static const unsigned char zvm6[] = {
77 		/* This is "z/VM    6" in EBCDIC */
78 		0xa9, 0x61, 0xe5, 0xd4, 0x40, 0x40, 0x40, 0x40, 0xf6
79 	};
80 
81 	if (stsi(pagebuf, 3, 2, 2))
82 		return false;
83 
84 	dcbt = pagebuf[31] & 0xf;
85 
86 	for (nr = 0; nr < dcbt; nr++) {
87 		if (!memcmp(&pagebuf[32 + nr * 64 + 24], zvm6, sizeof(zvm6)))
88 			return true;
89 	}
90 
91 	return false;
92 }
93 
94 static void test_priv(void)
95 {
96 	union skey skey;
97 	bool is_zvm6 = check_for_zvm6();
98 
99 	memset(pagebuf, 0, PAGE_SIZE * 2);
100 	report_prefix_push("privileged");
101 	report_prefix_push("sske");
102 	expect_pgm_int();
103 	enter_pstate();
104 	set_storage_key(pagebuf, 0x30, 0);
105 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
106 	report_prefix_pop();
107 
108 	skey.val = get_storage_key(pagebuf);
109 	report("skey did not change on exception", skey.str.acc != 3);
110 
111 	report_prefix_push("iske");
112 	if (is_zvm6) {
113 		/* There is a known bug with z/VM 6, so skip the test there */
114 		report_skip("not working on z/VM 6");
115 	} else {
116 		expect_pgm_int();
117 		enter_pstate();
118 		get_storage_key(pagebuf);
119 		check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
120 	}
121 	report_prefix_pop();
122 
123 	report_prefix_pop();
124 }
125 
126 int main(void)
127 {
128 	report_prefix_push("skey");
129 	if (test_facility(169)) {
130 		report_skip("storage key removal facility is active");
131 		goto done;
132 	}
133 	test_priv();
134 	test_set();
135 	test_set_mb();
136 	test_chg();
137 done:
138 	report_prefix_pop();
139 	return report_summary();
140 }
141