xref: /kvm-unit-tests/powerpc/cstart64.S (revision e521b10727bd6233dfc94b1ef4058a0d19b791e3)
1/*
2 * Entry point and assembler functions for ppc64 tests.
3 *
4 * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
5 *
6 * This work is licensed under the terms of the GNU LGPL, version 2.
7 */
8#define __ASSEMBLY__
9#include <asm/hcall.h>
10#include <asm/ppc_asm.h>
11#include <asm/rtas.h>
12#include <asm/ptrace.h>
13
14#include "spapr.h"
15
16#define P_HANDLER	0x2ff8
17
18.section .init
19
20/*
21 * start is the entry point. r3 points to the DTB
22 */
23.globl start
24start:
25	FIXUP_ENDIAN
26	/* Switch to 64-bit mode */
27	mfmsr	r1
28	li	r2,1
29	sldi	r2,r2,MSR_SF_BIT
30	or	r1,r1,r2
31	mtmsrd	r1
32	/*
33	 * We were loaded at QEMU's kernel load address, but we're not
34	 * allowed to link there due to how QEMU deals with linker VMAs,
35	 * so we just linked at zero. This means the first thing to do is
36	 * to find our stack and toc, and then do a relocate. powernv and
37	 * pseries load addresses are not the same, so find the address
38	 * dynamically:
39	 */
40	bl	0f
410:	mflr	r31
42	subi	r31, r31, 0b - start	/* QEMU's kernel load address */
43
44	ld	r1, (p_stack - start)(r31)
45	ld	r2, (p_toc - start)(r31)
46	add	r1, r1, r31
47	add	r2, r2, r31
48
49	/* Zero backpointers in initial stack frame so backtrace() stops */
50	li	r0,0
51	std	r0,0(r1)
52	std	r0,16(r1)
53
54	/* save DTB pointer */
55	std	r3, 56(r1)
56
57	/*
58	 * Call relocate. relocate is C code, but careful to not use
59	 * any global references, as they may use absolute addresses,
60	 * which are, obviously, not yet relocated.
61	 */
62	mr	r3, r31
63	ld	r4, (p_dyn - start)(r31)
64	add	r4, r4, r31
65	bl	relocate
66
67	/* compute address of call_handler */
68
69	LOAD_REG_ADDR(r4, call_handler)
70	std	r4, P_HANDLER(0)
71
72	/* relocate vector table to base address 0x0 (MSR_IP = 0) */
73
74	/* source: r4, dest end: r5, destination: r6 */
75
76	LOAD_REG_ADDR(r4, __start_interrupts)
77	LOAD_REG_ADDR(r5, __end_interrupts)
78	sub	r5,r5,r4
79	li	r6,0x100
80
81	sub	r4,r4,r6
82	add	r5,r5,r6
83	addi	r6,r6,-8
842:	li	r0,8
85	mtctr	r0
86	/* copy a cache line size */
873:	addi	r6,r6,8
88	ldx	r0,r6,r4
89	stdx	r0,0,r6
90	bdnz	3b
91	dcbst	0,r6
92	/* flush icache */
93	sync
94	icbi	0,r6
95	cmpld	0,r6,r5
96	blt	2b
97	sync
98	isync
99
100	/* powernv machine does not check broken_sc1 */
101	mfmsr	r3
102	li	r4,1
103	sldi	r4,r4,MSR_HV_BIT
104	and.	r3,r3,r4
105	bne	1f
106
107	/* patch sc1 if needed */
108	bl	hcall_have_broken_sc1
109	cmpwi	r3, 0
110	beq	1f
111	LOAD_REG_ADDR(r3, hcall)
112	LOAD_REG_IMMEDIATE(r4, SC1_REPLACEMENT)
113	stw	r4, 0(r3)
114
115	/* complete setup */
1161:	ld	r3, 56(r1)
117	bl	setup
118
119	/* run the test */
120	LOAD_REG_ADDR(r3, __argc)
121	LOAD_REG_ADDR(r4, __argv)
122	LOAD_REG_ADDR(r5, __environ)
123	lwz	r3, 0(r3)
124	bl	main
125	bl	exit
126	b	halt
127
128/*
129 * start_secondary is the secondary entry point. r3 contains the cpu id
130 */
131.globl start_secondary
132start_secondary:
133	FIXUP_ENDIAN
134	/* Switch to 64-bit mode */
135	mfmsr	r1
136	li	r2,1
137	sldi	r2,r2,MSR_SF_BIT
138	or	r1,r1,r2
139	mtmsrd	r1
140
141	bl	0f
1420:	mflr	r31
143	subi	r31, r31, 0b - start	/* QEMU's kernel load address */
144
145	ld	r2, (p_toc - start)(r31)
146
147	LOAD_REG_ADDR(r9, cpus)
148	li	r8,0
149	li	r7,0
1501:	add	r6,r9,r7
151	ld	r6,CPU_SERVER_NO(r6)
152	cmpd	r6,r3
153	beq	2f
154	addi	r7,r7,SIZEOF_STRUCT_CPU
155	addi	r8,r8,1
156	cmpdi	r8,MAX_CPUS
157	bne	1b
158	b	.
159
1602:	add	r3,r9,r7
161	ld	r1,CPU_STACK(r3)
162
163	/* Zero backpointers in initial stack frame so backtrace() stops */
164	li	r0,0
165	std	r0,0(r1)
166	std	r0,16(r1)
167
168	bl	main_secondary
169	bl	exit
170	b	halt
171
172.align 3
173p_stack:	.llong  stackptr
174p_toc:		.llong  tocptr
175p_dyn:		.llong  dynamic_start
176
177.text
178start_text:
179.align 3
180p_toc_text:	.llong	tocptr
181
182.align 3
183.globl hcall
184hcall:
185	sc	1
186	blr
187
188.globl halt
189halt:
1901:	b	1b
191
192.globl enter_rtas
193enter_rtas:
194	LOAD_REG_ADDR(r11, rtas_entry)
195	ld	r10, 0(r11)
196
197	cmpdi	r10,0
198	bne	external_rtas
199
200	/* Use H_RTAS directly */
201	mr	r4,r3
202	lis	r3,KVMPPC_H_RTAS@h
203	ori	r3,r3,KVMPPC_H_RTAS@l
204	b	hcall
205
206external_rtas:
207	/* Use external RTAS blob */
208	mflr	r0
209	std	r0, 16(r1)
210
211	LOAD_REG_ADDR(r11, rtas_return_loc)
212	mtlr	r11
213
214	mfmsr	r11
215	LOAD_REG_IMMEDIATE(r9, RTAS_MSR_MASK)
216	and	r11, r11, r9
217	mtsrr0	r10
218	mtsrr1	r11
219	rfid
220	b       .
221
222rtas_return_loc:
223	FIXUP_ENDIAN
224	ld	r0, 16(r1)
225	mtlr	r0
226	blr
227
228call_handler:
229	/* save context */
230
231	/* GPRs */
232
233	.irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 \
234	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
235		SAVE_GPR(\i, r1)
236	.endr
237	mfsprg1	r0
238	std	r0,GPR1(r1)
239	std	r0,0(r1) /* Backchain from interrupt stack to regular stack */
240
241	/* lr, xer, ccr */
242
243	mflr	r0
244	std	r0,_LINK(r1)
245
246	mfxer	r0
247	std	r0,_XER(r1)
248
249	mfcr	r0
250	std	r0,_CCR(r1)
251
252	/* restore TOC pointer */
253	bl	0f
2540:	mflr	r31
255	subi	r31, r31, 0b - start_text
256	ld	r2, (p_toc_text - start_text)(r31)
257
258	/* call generic handler */
259
260	addi	r3,r1,STACK_FRAME_OVERHEAD
261	bl	do_handle_exception
262	.global do_handle_exception_return
263do_handle_exception_return:
264
265	/* restore context */
266
267	ld	r0,_CTR(r1)
268	mtctr	r0
269
270	ld	r0,_LINK(r1)
271	mtlr	r0
272
273	ld	r0,_XER(r1)
274	mtxer	r0
275
276	ld	r0,_CCR(r1)
277	mtcr	r0
278
279	ld	r0, _NIP(r1)
280	mtsrr0	r0
281
282	ld	r0, _MSR(r1)
283	mtsrr1	r0
284
285	.irp i, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 \
286	        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
287		REST_GPR(\i, r1)
288	.endr
289
290	/* restore r1, as we don't need it anymore */
291
292	REST_GPR(1,r1)
293
294	rfid
295	b .
296
297.section .text.ex
298
299/* [H]VECTOR must not be more than 8 instructions to fit in 0x20 vectors */
300.macro VECTOR vec
301	. = \vec
302
303	mtsprg1	r1	/* save r1 */
304	mfsprg0	r1	/* get struct cpu address */
305	ld	r1,CPU_EXCEPTION_STACK(r1) /* get exception stack address */
306	subi	r1,r1, INT_FRAME_SIZE
307
308	/* save r0 and ctr to call generic handler */
309	SAVE_GPR(0,r1)
310
311	li	r0,\vec
312	std	r0,_TRAP(r1)
313
314	b	handler_trampoline
315.endm
316
317.macro HVECTOR vec
318	. = \vec
319
320	mtsprg1	r1	/* save r1 */
321	mfsprg0	r1	/* get struct cpu address */
322	ld	r1,CPU_EXCEPTION_STACK(r1) /* get exception stack address */
323	subi	r1,r1, INT_FRAME_SIZE
324
325	/* save r0 and ctr to call generic handler */
326	SAVE_GPR(0,r1)
327
328	li	r0,\vec
329	std	r0,_TRAP(r1)
330
331	b	handler_htrampoline
332.endm
333
334	. = 0x100
335	.globl __start_interrupts
336__start_interrupts:
337
338VECTOR(0x100)
339VECTOR(0x200)
340VECTOR(0x300)
341VECTOR(0x380)
342VECTOR(0x400)
343VECTOR(0x480)
344VECTOR(0x500)
345VECTOR(0x600)
346VECTOR(0x700)
347VECTOR(0x800)
348VECTOR(0x900)
349HVECTOR(0x980)
350VECTOR(0xa00)
351VECTOR(0xc00)
352VECTOR(0xd00)
353HVECTOR(0xe00)
354HVECTOR(0xe20)
355HVECTOR(0xe40)
356HVECTOR(0xe60)
357HVECTOR(0xe80)
358HVECTOR(0xea0)
359VECTOR(0xf00)
360VECTOR(0xf20)
361VECTOR(0xf40)
362VECTOR(0xf60)
363HVECTOR(0xf80)
364
365handler_trampoline:
366	mfctr	r0
367	std	r0,_CTR(r1)
368
369	ld	r0, P_HANDLER(0)
370	mtctr	r0
371
372	/* nip and msr */
373	mfsrr0	r0
374	std	r0, _NIP(r1)
375
376	mfsrr1	r0
377	std	r0, _MSR(r1)
378
379	bctr
380
381handler_htrampoline:
382	mfctr	r0
383	std	r0,_CTR(r1)
384
385	ld	r0, P_HANDLER(0)
386	mtctr	r0
387
388	/* nip and msr */
389	mfspr	r0, SPR_HSRR0
390	std	r0, _NIP(r1)
391
392	mfspr	r0, SPR_HSRR1
393	std	r0, _MSR(r1)
394
395	bctr
396
397	.align 7
398	.globl __end_interrupts
399__end_interrupts:
400	.org	P_HANDLER
401	.llong	0
402