xref: /kvm-unit-tests/powerpc/emulator.c (revision 52266791750d89b7f4ab6bad4d42de0056e4fb32)
1 /*
2  * Test some powerpc instructions
3  */
4 
5 #include <libcflat.h>
6 #include <asm/processor.h>
7 
8 static int verbose;
9 static int volatile is_invalid;
10 static int volatile alignment;
11 
12 static void program_check_handler(struct pt_regs *regs, void *opaque)
13 {
14 	int *data = opaque;
15 
16 	if (verbose) {
17 		printf("Detected invalid instruction 0x%016lx: %08x\n",
18 		       regs->nip, *(uint32_t*)regs->nip);
19 	}
20 
21 	/* the result is bit 16 to 19 of SRR1
22 	 * bit 0: SRR0 contains the address of the next instruction
23 	 * bit 1: Trap
24 	 * bit 2: Privileged instruction
25 	 * bit 3: Illegal instruction
26 	 * bit 4: FP enabled exception type
27 	 */
28 
29 	*data = regs->msr >> 16;
30 
31 	regs->nip += 4;
32 }
33 
34 static void alignment_handler(struct pt_regs *regs, void *opaque)
35 {
36 	int *data = opaque;
37 
38 	if (verbose) {
39 		printf("Detected alignment exception 0x%016lx: %08x\n",
40 		       regs->nip, *(uint32_t*)regs->nip);
41 	}
42 
43 	*data = 1;
44 
45 	regs->nip += 4;
46 }
47 
48 static void test_illegal(void)
49 {
50 	report_prefix_push("invalid");
51 
52 	is_invalid = 0;
53 
54 	asm volatile (".long 0");
55 
56 	report("exception", is_invalid == 8); /* illegal instruction */
57 
58 	report_prefix_pop();
59 }
60 
61 static void test_64bit(void)
62 {
63 	uint64_t msr;
64 
65 	report_prefix_push("64bit");
66 
67 	asm("mfmsr %[msr]": [msr] "=r" (msr));
68 
69 	report("detected", msr & 0x8000000000000000UL);
70 
71 	report_prefix_pop();
72 }
73 
74 /*
75  * lswx: Load String Word Indexed X-form
76  *
77  *     lswx RT,RA,RB
78  *
79  * EA = (RA|0) + RB
80  * n  = XER
81  *
82  * Load n bytes from address EA into (n / 4) consecutive registers,
83  * throught RT -> RT + (n / 4) - 1.
84  * - Data are loaded into 4 low order bytes of registers (Word).
85  * - The unfilled bytes are set to 0.
86  * - The sequence of registers wraps around to GPR0.
87  * - if n == 0, content of RT is undefined
88  * - RT <= RA or RB < RT + (n + 4) is invalid or result is undefined
89  * - RT == RA == 0 is invalid
90  *
91  * For lswx in little-endian mode, an alignment interrupt always occurs.
92  *
93  */
94 
95 static void test_lswx(void)
96 {
97 	int i;
98 	char addr[128];
99 	uint64_t regs[32];
100 
101 	report_prefix_push("lswx");
102 
103 	/* fill memory with sequence */
104 
105 	for (i = 0; i < 128; i++)
106 		addr[i] = 1 + i;
107 
108 	/* check incomplete register filling */
109 
110 	alignment = 0;
111 	asm volatile ("mtxer %[len];"
112 		      "li r12,-1;"
113 		      "mr r11, r12;"
114 		      "lswx r11, 0, %[addr];"
115 		      "std r11, 0*8(%[regs]);"
116 		      "std r12, 1*8(%[regs]);"
117 		      ::
118 		      [len] "r" (3),
119 		      [addr] "r" (addr),
120 		      [regs] "r" (regs)
121 		      :
122 		      "xer", "r11", "r12", "memory");
123 
124 #if  __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
125 	report("alignment", alignment);
126 	return;
127 #else
128 	report("partial", regs[0] == 0x01020300 && regs[1] == (uint64_t)-1);
129 #endif
130 
131 	/* check an old know bug: the number of bytes is used as
132 	 * the number of registers, so try 32 bytes.
133 	 */
134 
135 	asm volatile ("mtxer %[len];"
136 		      "li r19,-1;"
137 		      "mr r11, r19; mr r12, r19; mr r13, r19;"
138 		      "mr r14, r19; mr r15, r19; mr r16, r19;"
139 		      "mr r17, r19; mr r18, r19;"
140 		      "lswx r11, 0, %[addr];"
141 		      "std r11, 0*8(%[regs]);"
142 		      "std r12, 1*8(%[regs]);"
143 		      "std r13, 2*8(%[regs]);"
144 		      "std r14, 3*8(%[regs]);"
145 		      "std r15, 4*8(%[regs]);"
146 		      "std r16, 5*8(%[regs]);"
147 		      "std r17, 6*8(%[regs]);"
148 		      "std r18, 7*8(%[regs]);"
149 		      "std r19, 8*8(%[regs]);"
150 		      ::
151 		      [len] "r" (32),
152 		      [addr] "r" (addr),
153 		      [regs] "r" (regs)
154 		      :
155 		      /* as 32 is the number of bytes,
156 		       * we should modify 32/4 = 8 regs, from r11 to r18
157 		       * We check r19 is unmodified by filling it with 1s
158 		       * before the instruction.
159 		       */
160 		      "xer", "r11", "r12", "r13", "r14", "r15", "r16", "r17",
161 		      "r18", "r19", "memory");
162 
163 	report("length", regs[0] == 0x01020304 && regs[1] == 0x05060708 &&
164 			 regs[2] == 0x090a0b0c && regs[3] == 0x0d0e0f10 &&
165 			 regs[4] == 0x11121314 && regs[5] == 0x15161718 &&
166 			 regs[6] == 0x191a1b1c && regs[7] == 0x1d1e1f20 &&
167 			 regs[8] == (uint64_t)-1);
168 
169 	/* check wrap around to r0 */
170 
171 	asm volatile ("mtxer %[len];"
172 		      "li r31,-1;"
173 		      "mr r0, r31;"
174 		      "lswx r31, 0, %[addr];"
175 		      "std r31, 0*8(%[regs]);"
176 		      "std r0, 1*8(%[regs]);"
177 		      ::
178 		      [len] "r" (8),
179 		      [addr] "r" (addr),
180 		      [regs] "r" (regs)
181 		      :
182 		      /* modify two registers from r31, wrap around to r0 */
183 		      "xer", "r31", "r0", "memory");
184 
185 	report("wrap around to r0", regs[0] == 0x01020304 &&
186 			            regs[1] == 0x05060708);
187 
188 	/* check wrap around to r0 over RB doesn't break RB */
189 
190 	asm volatile ("mtxer %[len];"
191 		      "mr r29,r1;"
192 		      "li r31,-1;"
193 		      "mr r1,r31;"
194 		      "mr r0, %[addr];"
195 		      "lswx r31, 0, r0;"
196 		      "std r31, 0*8(%[regs]);"
197 		      "std r0, 1*8(%[regs]);"
198 		      "std r1, 2*8(%[regs]);"
199 		      "mr r1,r29;"
200 		      ::
201 		      [len] "r" (12),
202 		      [addr] "r" (addr),
203 		      [regs] "r" (regs)
204 		      :
205 		      /* loading three registers from r31 wraps around to r1,
206 		       * r1 is saved to r29, as adding it to the clobber
207 		       * list doesn't protect it
208 		       */
209 		      "xer", "r31", "r0", "r29", "memory");
210 
211 	/* doc says it is invalid, real proc stops when it comes to
212 	 * overwrite the register.
213 	 * In all the cases, the register must stay untouched
214 	 */
215 	report("Don't overwrite Rb", regs[1] == (uint64_t)addr);
216 
217 	report_prefix_pop();
218 }
219 
220 int main(int argc, char **argv)
221 {
222 	int i;
223 
224 	handle_exception(0x700, program_check_handler, (void *)&is_invalid);
225 	handle_exception(0x600, alignment_handler, (void *)&alignment);
226 
227 	for (i = 0; i < argc; i++) {
228 		if (strcmp(argv[i], "-v") == 0) {
229 			verbose = 1;
230 		}
231 	}
232 
233 	report_prefix_push("emulator");
234 
235 	test_64bit();
236 	test_illegal();
237 	test_lswx();
238 
239 	report_prefix_pop();
240 
241 	return report_summary();
242 }
243