xref: /kvm-unit-tests/s390x/pfmf.c (revision 832e1c1596445f17d1542fc89aba81419154a4ca)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Perform Frame Management Function (pfmf) tests
4  *
5  * Copyright (c) 2018 IBM
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 static uint8_t pagebuf[PAGE_SIZE * 256] __attribute__((aligned(PAGE_SIZE * 256)));
18 
19 static void test_priv(void)
20 {
21 	report_prefix_push("privileged");
22 	expect_pgm_int();
23 	enter_pstate();
24 	pfmf(0, pagebuf);
25 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
26 	report_prefix_pop();
27 }
28 
29 static void test_4k_key(void)
30 {
31 	union pfmf_r1 r1;
32 	union skey skey;
33 
34 	report_prefix_push("4K");
35 	if (test_facility(169)) {
36 		report_skip("storage key removal facility is active");
37 		goto out;
38 	}
39 	r1.val = 0;
40 	r1.reg.sk = 1;
41 	r1.reg.fsc = PFMF_FSC_4K;
42 	r1.reg.key = 0x30;
43 	pfmf(r1.val, pagebuf);
44 	skey.val = get_storage_key(pagebuf);
45 	skey.val &= SKEY_ACC | SKEY_FP;
46 	report(skey.val == 0x30, "set storage keys");
47 out:
48 	report_prefix_pop();
49 }
50 
51 static void test_1m_key(void)
52 {
53 	int i;
54 	bool rp = true;
55 	union pfmf_r1 r1;
56 	union skey skey;
57 
58 	report_prefix_push("1M");
59 	if (test_facility(169)) {
60 		report_skip("storage key removal facility is active");
61 		goto out;
62 	}
63 	r1.val = 0;
64 	r1.reg.sk = 1;
65 	r1.reg.fsc = PFMF_FSC_1M;
66 	r1.reg.key = 0x30;
67 	pfmf(r1.val, pagebuf);
68 	for (i = 0; i < 256; i++) {
69 		skey.val = get_storage_key(pagebuf + i * PAGE_SIZE);
70 		skey.val &= SKEY_ACC | SKEY_FP;
71 		if (skey.val != 0x30) {
72 			rp = false;
73 			break;
74 		}
75 	}
76 	report(rp, "set storage keys");
77 out:
78 	report_prefix_pop();
79 }
80 
81 static void test_4k_clear(void)
82 {
83 	union pfmf_r1 r1;
84 
85 	r1.val = 0;
86 	r1.reg.cf = 1;
87 	r1.reg.fsc = PFMF_FSC_4K;
88 
89 	report_prefix_push("4K");
90 	memset(pagebuf, 42, PAGE_SIZE);
91 	pfmf(r1.val, pagebuf);
92 	report(!memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE),
93 	       "clear memory");
94 	report_prefix_pop();
95 }
96 
97 static void test_1m_clear(void)
98 {
99 	int i;
100 	union pfmf_r1 r1;
101 	unsigned long sum = 0;
102 
103 	r1.val = 0;
104 	r1.reg.cf = 1;
105 	r1.reg.fsc = PFMF_FSC_1M;
106 
107 	report_prefix_push("1M");
108 	memset(pagebuf, 42, PAGE_SIZE * 256);
109 	pfmf(r1.val, pagebuf);
110 	for (i = 0; i < PAGE_SIZE * 256; i++)
111 		sum |= pagebuf[i];
112 	report(!sum, "clear memory");
113 	report_prefix_pop();
114 }
115 
116 static void test_low_addr_prot(void)
117 {
118 	union pfmf_r1 r1 = {
119 		.reg.cf = 1,
120 		.reg.fsc = PFMF_FSC_4K
121 	};
122 
123 	report_prefix_push("low-address protection");
124 
125 	report_prefix_push("0x1000");
126 	expect_pgm_int();
127 	low_prot_enable();
128 	pfmf(r1.val, (void *)0x1000);
129 	low_prot_disable();
130 	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
131 	report_prefix_pop();
132 
133 	report_prefix_push("0x0");
134 	expect_pgm_int();
135 	low_prot_enable();
136 	pfmf(r1.val, 0);
137 	low_prot_disable();
138 	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
139 	report_prefix_pop();
140 
141 	report_prefix_pop();
142 }
143 
144 int main(void)
145 {
146 	bool has_edat = test_facility(8);
147 
148 	report_prefix_push("pfmf");
149 	if (!has_edat) {
150 		report_skip("PFMF is not available");
151 		goto done;
152 	}
153 
154 	test_priv();
155 	test_low_addr_prot();
156 	/* Force the buffer pages in */
157 	memset(pagebuf, 0, PAGE_SIZE * 256);
158 
159 	test_4k_key();
160 	test_4k_clear();
161 	test_1m_key();
162 	test_1m_clear();
163 
164 done:
165 	report_prefix_pop();
166 	return report_summary();
167 }
168