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