xref: /kvm-unit-tests/s390x/pfmf.c (revision 06846df56370af39fb4c9cfd71c032197133929b)
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 #define FSC_4K 0
20 #define FSC_1M 1
21 #define FSC_2G 2
22 
23 union r1 {
24 	struct {
25 		unsigned long pad0 : 32;
26 		unsigned long pad1 : 12;
27 		unsigned long pad_fmfi : 2;
28 		unsigned long sk : 1; /* set key*/
29 		unsigned long cf : 1; /* clear frame */
30 		unsigned long ui : 1; /* usage indication */
31 		unsigned long fsc : 3;
32 		unsigned long pad2 : 1;
33 		unsigned long mr : 1;
34 		unsigned long mc : 1;
35 		unsigned long pad3 : 1;
36 		unsigned long key : 8; /* storage keys */
37 	} reg;
38 	unsigned long val;
39 };
40 
41 static uint8_t pagebuf[PAGE_SIZE * 256] __attribute__((aligned(PAGE_SIZE * 256)));
42 
43 static inline unsigned long pfmf(unsigned long r1, unsigned long paddr)
44 {
45 	register uint64_t addr asm("1") = paddr;
46 
47 	asm volatile(".insn rre,0xb9af0000,%[r1],%[addr]"
48 		     : [addr] "+a" (addr) : [r1] "d" (r1) : "memory");
49 	return addr;
50 }
51 
52 static void test_priv(void)
53 {
54 	report_prefix_push("privileged");
55 	expect_pgm_int();
56 	enter_pstate();
57 	pfmf(0, (unsigned long) pagebuf);
58 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
59 	report_prefix_pop();
60 }
61 
62 static void test_4k_key(void)
63 {
64 	union r1 r1;
65 	union skey skey;
66 
67 	r1.val = 0;
68 	r1.reg.sk = 1;
69 	r1.reg.fsc = FSC_4K;
70 	r1.reg.key = 0x30;
71 	pfmf(r1.val, (unsigned long) pagebuf);
72 	skey.val = get_storage_key((unsigned long) pagebuf);
73 	report("set 4k", skey.val == 0x30);
74 }
75 
76 static void test_1m_key(void)
77 {
78 	int i;
79 	union r1 r1;
80 
81 	r1.val = 0;
82 	r1.reg.sk = 1;
83 	r1.reg.fsc = FSC_1M;
84 	r1.reg.key = 0x30;
85 	pfmf(r1.val, (unsigned long) pagebuf);
86 	for (i = 0; i < 256; i++) {
87 		if (get_storage_key((unsigned long) pagebuf + i * PAGE_SIZE) != 0x30) {
88 			report("set 1M", false);
89 			return;
90 		}
91 	}
92 	report("set 1M", true);
93 }
94 
95 static void test_4k_clear(void)
96 {
97 	union r1 r1;
98 
99 	r1.val = 0;
100 	r1.reg.cf = 1;
101 	r1.reg.fsc = FSC_4K;
102 
103 	memset(pagebuf, 42, PAGE_SIZE);
104 	pfmf(r1.val, (unsigned long) pagebuf);
105 	report("clear 4k", !memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE));
106 }
107 
108 static void test_1m_clear(void)
109 {
110 	int i;
111 	union r1 r1;
112 	unsigned long sum = 0;
113 
114 	r1.val = 0;
115 	r1.reg.cf = 1;
116 	r1.reg.fsc = FSC_1M;
117 
118 	memset(pagebuf, 42, PAGE_SIZE * 256);
119 	pfmf(r1.val, (unsigned long) pagebuf);
120 	for (i = 0; i < PAGE_SIZE * 256; i++)
121 		sum |= pagebuf[i];
122 	report("clear 1m", !sum);
123 }
124 
125 int main(void)
126 {
127 	bool has_edat = test_facility(8);
128 
129 	report_prefix_push("pfmf");
130 	if (!has_edat) {
131 		report_skip("PFMF is not available");
132 		goto done;
133 	}
134 
135 	test_priv();
136 	/* Force the buffer pages in */
137 	memset(pagebuf, 0, PAGE_SIZE * 256);
138 
139 	test_4k_key();
140 	test_1m_key();
141 	test_4k_clear();
142 	test_1m_clear();
143 
144 done:
145 	report_prefix_pop();
146 	return report_summary();
147 }
148