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