xref: /kvm-unit-tests/s390x/skey.c (revision 832e1c1596445f17d1542fc89aba81419154a4ca)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Storage key tests
4  *
5  * Copyright (c) 2018 IBM Corp
6  *
7  * Authors:
8  *  Janosch Frank <frankja@linux.vnet.ibm.com>
9  */
10 #include <libcflat.h>
11 #include <asm/asm-offsets.h>
12 #include <asm/interrupt.h>
13 #include <asm/page.h>
14 #include <asm/facility.h>
15 #include <asm/mem.h>
16 
17 
18 static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
19 
20 static void test_set_mb(void)
21 {
22 	union skey skey, ret1, ret2;
23 	void *addr = (void *)0x10000 - 2 * PAGE_SIZE;
24 	void *end = (void *)0x10000;
25 
26 	/* Multi block support came with EDAT 1 */
27 	if (!test_facility(8))
28 		return;
29 
30 	skey.val = 0x30;
31 	while (addr < end)
32 		addr = set_storage_key_mb(addr, skey.val);
33 
34 	ret1.val = get_storage_key(end - PAGE_SIZE) & (SKEY_ACC | SKEY_FP);
35 	ret2.val = get_storage_key(end - PAGE_SIZE * 2) & (SKEY_ACC | SKEY_FP);
36 	report(ret1.val == ret2.val && ret1.val == skey.val, "multi block");
37 }
38 
39 static void test_chg(void)
40 {
41 	union skey skey1, skey2;
42 
43 	skey1.val = 0x30;
44 	set_storage_key(pagebuf, skey1.val, 0);
45 	skey1.val = get_storage_key(pagebuf);
46 	pagebuf[0] = 3;
47 	skey2.val = get_storage_key(pagebuf);
48 	report(!skey1.str.ch && skey2.str.ch, "chg bit test");
49 }
50 
51 static void test_set(void)
52 {
53 	union skey skey, ret;
54 
55 	skey.val = 0x30;
56 	ret.val = get_storage_key(pagebuf);
57 	set_storage_key(pagebuf, skey.val, 0);
58 	ret.val = get_storage_key(pagebuf);
59 	/*
60 	 * For all set tests we only test the ACC and FP bits. RF and
61 	 * CH are set by the machine for memory references and changes
62 	 * and hence might change between a set and a get.
63 	 */
64 	report(skey.str.acc == ret.str.acc && skey.str.fp == ret.str.fp,
65 	       "set key test");
66 }
67 
68 static void test_priv(void)
69 {
70 	union skey skey;
71 
72 	memset(pagebuf, 0, PAGE_SIZE * 2);
73 	report_prefix_push("privileged");
74 	report_prefix_push("sske");
75 	expect_pgm_int();
76 	enter_pstate();
77 	set_storage_key(pagebuf, 0x30, 0);
78 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
79 	report_prefix_pop();
80 
81 	skey.val = get_storage_key(pagebuf);
82 	report(skey.str.acc != 3, "skey did not change on exception");
83 
84 	report_prefix_push("iske");
85 	expect_pgm_int();
86 	enter_pstate();
87 	get_storage_key(pagebuf);
88 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
89 	report_prefix_pop();
90 
91 	report_prefix_pop();
92 }
93 
94 static void test_invalid_address(void)
95 {
96 	void *inv_addr = (void *)-1ull;
97 
98 	report_prefix_push("invalid address");
99 
100 	report_prefix_push("sske");
101 	expect_pgm_int();
102 	set_storage_key(inv_addr, 0, 0);
103 	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
104 	report_prefix_pop();
105 
106 	report_prefix_push("iske");
107 	expect_pgm_int();
108 	get_storage_key(inv_addr);
109 	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
110 	report_prefix_pop();
111 
112 	report_prefix_push("rrbe");
113 	expect_pgm_int();
114 	reset_reference_bit(inv_addr);
115 	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
116 	report_prefix_pop();
117 
118 	report_prefix_pop();
119 }
120 
121 int main(void)
122 {
123 	report_prefix_push("skey");
124 	if (test_facility(169)) {
125 		report_skip("storage key removal facility is active");
126 		goto done;
127 	}
128 	test_priv();
129 	test_invalid_address();
130 	test_set();
131 	test_set_mb();
132 	test_chg();
133 done:
134 	report_prefix_pop();
135 	return report_summary();
136 }
137