xref: /kvm-unit-tests/powerpc/emulator.c (revision cd27b4baa5e1b8e1bc3c2e1f25bf820bd9b3d5a9)
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 
program_check_handler(struct pt_regs * regs,void * opaque)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 %#018lx: %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 
heai_handler(struct pt_regs * regs,void * opaque)34 static void heai_handler(struct pt_regs *regs, void *opaque)
35 {
36 	int *data = opaque;
37 
38 	if (verbose) {
39 		printf("Detected invalid instruction %#018lx: %08x\n",
40 		       regs->nip, *(uint32_t*)regs->nip);
41 	}
42 
43 	*data = 8; /* Illegal instruction */
44 
45 	regs->nip += 4;
46 }
47 
alignment_handler(struct pt_regs * regs,void * opaque)48 static void alignment_handler(struct pt_regs *regs, void *opaque)
49 {
50 	int *data = opaque;
51 
52 	if (verbose) {
53 		printf("Detected alignment exception %#018lx: %08x\n",
54 		       regs->nip, *(uint32_t*)regs->nip);
55 	}
56 
57 	*data = 1;
58 
59 	regs->nip += 4;
60 }
61 
test_illegal(void)62 static void test_illegal(void)
63 {
64 	report_prefix_push("invalid");
65 
66 	is_invalid = 0;
67 
68 	asm volatile (".long 0");
69 
70 	report(is_invalid == 8, "exception"); /* illegal instruction */
71 
72 	report_prefix_pop();
73 }
74 
test_64bit(void)75 static void test_64bit(void)
76 {
77 	uint64_t msr;
78 
79 	report_prefix_push("64bit");
80 
81 	asm("mfmsr %[msr]": [msr] "=r" (msr));
82 
83 	report(msr & 0x8000000000000000UL, "detected");
84 
85 	report_prefix_pop();
86 }
87 
88 /*
89  * Test 'Load String Word Immediate' instruction
90  */
test_lswi(void)91 static void test_lswi(void)
92 {
93 	int i;
94 	char addr[128];
95 	uint64_t regs[32];
96 
97 	report_prefix_push("lswi");
98 
99 	/* fill memory with sequence */
100 	for (i = 0; i < 128; i++)
101 		addr[i] = 1 + i;
102 
103 #if  __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
104 
105 	/*
106 	 * lswi is supposed to cause an alignment exception in little endian
107 	 * mode, but to be able to check this, we also have to specify the
108 	 * opcode without mnemonic here since newer versions of GCC refuse
109 	 * "lswi" when compiling in little endian mode.
110 	 */
111 	alignment = 0;
112 	asm volatile ("mr r12,%[addr];"
113 		      ".long 0x7d6c24aa;"       /* lswi r11,r12,4 */
114 		      "std r11,0(%[regs]);"
115 		       :: [addr] "r" (addr), [regs] "r" (regs)
116 		       : "r11", "r12", "memory");
117 	report(alignment, "alignment");
118 
119 #else
120 
121 	/* check incomplete register filling */
122 	asm volatile ("li r12,-1;"
123 		      "mr r11, r12;"
124 		      "lswi r11, %[addr], %[len];"
125 		      "std r11, 0*8(%[regs]);"
126 		      "std r12, 1*8(%[regs]);"
127 		      ::
128 		      [len] "i" (3),
129 		      [addr] "b" (addr),
130 		      [regs] "r" (regs)
131 		      :
132 		      "r11", "r12", "memory");
133 	report(regs[0] == 0x01020300 && regs[1] == (uint64_t)-1, "partial");
134 
135 	/* check NB = 0 ==> 32 bytes. */
136 	asm volatile ("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 		      "lswi r11, %[addr], %[len];"
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] "i" (0),
152 		      [addr] "b" (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 		      "r11", "r12", "r13", "r14", "r15", "r16", "r17",
161 		      "r18", "r19", "memory");
162 
163 	report(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, "length");
168 
169 	/* check wrap around to r0 */
170 	asm volatile ("li r31,-1;"
171 		      "mr r0, r31;"
172 		      "lswi r31, %[addr], %[len];"
173 		      "std r31, 0*8(%[regs]);"
174 		      "std r0, 1*8(%[regs]);"
175 		      ::
176 		      [len] "i" (8),
177 		      [addr] "b" (addr),
178 		      [regs] "r" (regs)
179 		      :
180 		      /* modify two registers from r31, wrap around to r0 */
181 		      "r31", "r0", "memory");
182 
183 	report(regs[0] == 0x01020304 && regs[1] == 0x05060708,
184 	       "wrap around to r0");
185 
186 	/* check wrap around doesn't break RA */
187 	asm volatile ("mr r29,r1\n"
188 		      "li r31,-1\n"
189 		      "mr r0,r31\n"
190 		      "mr r1, %[addr]\n"
191 		      ".long 0x7fe154aa\n"       /* lswi r31, r1, 10 */
192 		      "std r31, 0*8(%[regs])\n"
193 		      "std r0, 1*8(%[regs])\n"
194 		      "std r1, 2*8(%[regs])\n"
195 		      "mr r1,r29\n"
196 		      ::
197 		      [addr] "r" (addr),
198 		      [regs] "r" (regs)
199 		      :
200 		      /* loading three registers from r31 wraps around to r1,
201 		       * r1 is saved to r29, as adding it to the clobber
202 		       * list doesn't protect it
203 		       */
204 		      "r0", "r29", "r31", "memory");
205 
206 	/* doc says it is invalid, real proc stops when it comes to
207 	 * overwrite the register.
208 	 * In all the cases, the register must stay untouched
209 	 */
210 	report(regs[2] == (uint64_t)addr, "Don't overwrite Ra");
211 
212 #endif
213 
214 	report_prefix_pop();
215 }
216 
217 /*
218  * lswx: Load String Word Indexed X-form
219  *
220  *     lswx RT,RA,RB
221  *
222  * EA = (RA|0) + RB
223  * n  = XER
224  *
225  * Load n bytes from address EA into (n / 4) consecutive registers,
226  * throught RT -> RT + (n / 4) - 1.
227  * - Data are loaded into 4 low order bytes of registers (Word).
228  * - The unfilled bytes are set to 0.
229  * - The sequence of registers wraps around to GPR0.
230  * - if n == 0, content of RT is undefined
231  * - RT <= RA or RB < RT + (n + 4) is invalid or result is undefined
232  * - RT == RA == 0 is invalid
233  *
234  * For lswx in little-endian mode, an alignment interrupt always occurs.
235  *
236  */
237 
test_lswx(void)238 static void test_lswx(void)
239 {
240 	int i;
241 	char addr[128];
242 	uint64_t regs[32];
243 
244 	report_prefix_push("lswx");
245 
246 	/* fill memory with sequence */
247 	for (i = 0; i < 128; i++)
248 		addr[i] = 1 + i;
249 
250 #if  __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
251 
252 	/*
253 	 * lswx is supposed to cause an alignment exception in little endian
254 	 * mode, but to be able to check this, we also have to specify the
255 	 * opcode without mnemonic here since newer versions of GCC refuse
256 	 * "lswx" when compiling in little endian mode.
257 	 */
258 	alignment = 0;
259 	asm volatile ("mtxer %[len];"
260 		      "mr r11,%[addr];"
261 		      ".long 0x7d805c2a;"       /* lswx r12,0,r11 */
262 		      "std r12,0(%[regs]);"
263 		      :: [len]"r"(4), [addr]"r"(addr), [regs]"r"(regs)
264 		      : "r11", "r12", "memory");
265 	report(alignment, "alignment");
266 
267 #else
268 
269 	/* check incomplete register filling */
270 	asm volatile ("mtxer %[len];"
271 		      "li r12,-1;"
272 		      "mr r11, r12;"
273 		      "lswx r11, 0, %[addr];"
274 		      "std r11, 0*8(%[regs]);"
275 		      "std r12, 1*8(%[regs]);"
276 		      ::
277 		      [len] "r" (3),
278 		      [addr] "r" (addr),
279 		      [regs] "r" (regs)
280 		      :
281 		      "xer", "r11", "r12", "memory");
282 	report(regs[0] == 0x01020300 && regs[1] == (uint64_t)-1, "partial");
283 
284 	/* check an old know bug: the number of bytes is used as
285 	 * the number of registers, so try 32 bytes.
286 	 */
287 
288 	asm volatile ("mtxer %[len];"
289 		      "li r19,-1;"
290 		      "mr r11, r19; mr r12, r19; mr r13, r19;"
291 		      "mr r14, r19; mr r15, r19; mr r16, r19;"
292 		      "mr r17, r19; mr r18, r19;"
293 		      "lswx r11, 0, %[addr];"
294 		      "std r11, 0*8(%[regs]);"
295 		      "std r12, 1*8(%[regs]);"
296 		      "std r13, 2*8(%[regs]);"
297 		      "std r14, 3*8(%[regs]);"
298 		      "std r15, 4*8(%[regs]);"
299 		      "std r16, 5*8(%[regs]);"
300 		      "std r17, 6*8(%[regs]);"
301 		      "std r18, 7*8(%[regs]);"
302 		      "std r19, 8*8(%[regs]);"
303 		      ::
304 		      [len] "r" (32),
305 		      [addr] "r" (addr),
306 		      [regs] "r" (regs)
307 		      :
308 		      /* as 32 is the number of bytes,
309 		       * we should modify 32/4 = 8 regs, from r11 to r18
310 		       * We check r19 is unmodified by filling it with 1s
311 		       * before the instruction.
312 		       */
313 		      "xer", "r11", "r12", "r13", "r14", "r15", "r16", "r17",
314 		      "r18", "r19", "memory");
315 
316 	report(regs[0] == 0x01020304 && regs[1] == 0x05060708 &&
317 	       regs[2] == 0x090a0b0c && regs[3] == 0x0d0e0f10 &&
318 	       regs[4] == 0x11121314 && regs[5] == 0x15161718 &&
319 	       regs[6] == 0x191a1b1c && regs[7] == 0x1d1e1f20 &&
320 	       regs[8] == (uint64_t)-1, "length");
321 
322 	/* check wrap around to r0 */
323 
324 	asm volatile ("mtxer %[len];"
325 		      "li r31,-1;"
326 		      "mr r0, r31;"
327 		      "lswx r31, 0, %[addr];"
328 		      "std r31, 0*8(%[regs]);"
329 		      "std r0, 1*8(%[regs]);"
330 		      ::
331 		      [len] "r" (8),
332 		      [addr] "r" (addr),
333 		      [regs] "r" (regs)
334 		      :
335 		      /* modify two registers from r31, wrap around to r0 */
336 		      "xer", "r31", "r0", "memory");
337 
338 	report(regs[0] == 0x01020304 && regs[1] == 0x05060708,
339 	       "wrap around to r0");
340 
341 	/* check wrap around to r0 over RB doesn't break RB */
342 
343 	asm volatile ("mtxer %[len];"
344 		      "mr r29,r1;"
345 		      "li r31,-1;"
346 		      "mr r1,r31;"
347 		      "mr r0, %[addr];"
348 		      "lswx r31, 0, r0;"
349 		      "std r31, 0*8(%[regs]);"
350 		      "std r0, 1*8(%[regs]);"
351 		      "std r1, 2*8(%[regs]);"
352 		      "mr r1,r29;"
353 		      ::
354 		      [len] "r" (12),
355 		      [addr] "r" (addr),
356 		      [regs] "r" (regs)
357 		      :
358 		      /* loading three registers from r31 wraps around to r1,
359 		       * r1 is saved to r29, as adding it to the clobber
360 		       * list doesn't protect it
361 		       */
362 		      "xer", "r31", "r0", "r29", "memory");
363 
364 	/* doc says it is invalid, real proc stops when it comes to
365 	 * overwrite the register.
366 	 * In all the cases, the register must stay untouched
367 	 */
368 	report(regs[1] == (uint64_t)addr, "Don't overwrite Rb");
369 
370 #endif
371 
372 	report_prefix_pop();
373 }
374 
main(int argc,char ** argv)375 int main(int argc, char **argv)
376 {
377 	int i;
378 
379 	handle_exception(0x700, program_check_handler, (void *)&is_invalid);
380 	if (cpu_has_heai)
381 		handle_exception(0xe40, heai_handler, (void *)&is_invalid);
382 	handle_exception(0x600, alignment_handler, (void *)&alignment);
383 
384 	for (i = 1; i < argc; i++) {
385 		if (strcmp(argv[i], "-v") == 0) {
386 			verbose = 1;
387 		}
388 	}
389 
390 	report_prefix_push("emulator");
391 
392 	test_64bit();
393 	test_illegal();
394 	test_lswx();
395 	test_lswi();
396 
397 	report_prefix_pop();
398 
399 	return report_summary();
400 }
401