xref: /kvm-unit-tests/s390x/pfmf.c (revision 728e71ee457384eb1cf2d5111d1e4329498581db)
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 	expect_pgm_int();
55 	enter_pstate();
56 	pfmf(0, (unsigned long) pagebuf);
57 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
58 }
59 
60 static void test_4k_key(void)
61 {
62 	union r1 r1;
63 	union skey skey;
64 
65 	r1.val = 0;
66 	r1.reg.sk = 1;
67 	r1.reg.fsc = FSC_4K;
68 	r1.reg.key = 0x30;
69 	pfmf(r1.val, (unsigned long) pagebuf);
70 	skey.val = get_storage_key((unsigned long) pagebuf);
71 	report("set 4k", skey.val == 0x30);
72 }
73 
74 static void test_1m_key(void)
75 {
76 	int i;
77 	union r1 r1;
78 
79 	r1.val = 0;
80 	r1.reg.sk = 1;
81 	r1.reg.fsc = FSC_1M;
82 	r1.reg.key = 0x30;
83 	pfmf(r1.val, (unsigned long) pagebuf);
84 	for (i = 0; i < 256; i++) {
85 		if (get_storage_key((unsigned long) pagebuf + i * PAGE_SIZE) != 0x30) {
86 			report("set 1M", false);
87 			return;
88 		}
89 	}
90 	report("set 1M", true);
91 }
92 
93 static void test_4k_clear(void)
94 {
95 	union r1 r1;
96 
97 	r1.val = 0;
98 	r1.reg.cf = 1;
99 	r1.reg.fsc = FSC_4K;
100 
101 	memset(pagebuf, 42, PAGE_SIZE);
102 	pfmf(r1.val, (unsigned long) pagebuf);
103 	report("clear 4k", !memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE));
104 }
105 
106 static void test_1m_clear(void)
107 {
108 	int i;
109 	union r1 r1;
110 	unsigned long sum = 0;
111 
112 	r1.val = 0;
113 	r1.reg.cf = 1;
114 	r1.reg.fsc = FSC_1M;
115 
116 	memset(pagebuf, 42, PAGE_SIZE * 256);
117 	pfmf(r1.val, (unsigned long) pagebuf);
118 	for (i = 0; i < PAGE_SIZE * 256; i++)
119 		sum |= pagebuf[i];
120 	report("clear 1m", !sum);
121 }
122 
123 int main(void)
124 {
125 	bool has_edat = test_facility(8);
126 
127 	report_prefix_push("pfmf");
128 	if (!has_edat) {
129 		report_skip("PFMF is not available");
130 		goto done;
131 	}
132 
133 	test_priv();
134 	/* Force the buffer pages in */
135 	memset(pagebuf, 0, PAGE_SIZE * 256);
136 
137 	test_4k_key();
138 	test_1m_key();
139 	test_4k_clear();
140 	test_1m_clear();
141 
142 done:
143 	report_prefix_pop();
144 	return report_summary();
145 }
146