xref: /kvm-unit-tests/s390x/pfmf.c (revision a299895b7abb54e7ba6bb4108f202acbb484ac65)
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(skey.val == 0x30, "set storage keys");
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(rp, "set storage keys");
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(!memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE),
95 	       "clear memory");
96 	report_prefix_pop();
97 }
98 
99 static void test_1m_clear(void)
100 {
101 	int i;
102 	union pfmf_r1 r1;
103 	unsigned long sum = 0;
104 
105 	r1.val = 0;
106 	r1.reg.cf = 1;
107 	r1.reg.fsc = PFMF_FSC_1M;
108 
109 	report_prefix_push("1M");
110 	memset(pagebuf, 42, PAGE_SIZE * 256);
111 	pfmf(r1.val, pagebuf);
112 	for (i = 0; i < PAGE_SIZE * 256; i++)
113 		sum |= pagebuf[i];
114 	report(!sum, "clear memory");
115 	report_prefix_pop();
116 }
117 
118 int main(void)
119 {
120 	bool has_edat = test_facility(8);
121 
122 	report_prefix_push("pfmf");
123 	if (!has_edat) {
124 		report_skip("PFMF is not available");
125 		goto done;
126 	}
127 
128 	test_priv();
129 	/* Force the buffer pages in */
130 	memset(pagebuf, 0, PAGE_SIZE * 256);
131 
132 	test_4k_key();
133 	test_4k_clear();
134 	test_1m_key();
135 	test_1m_clear();
136 
137 done:
138 	report_prefix_pop();
139 	return report_summary();
140 }
141