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