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