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