1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Code to process dynamic relocations in the kernel.
4 *
5 * Copyright 2008 Paul Mackerras, IBM Corp.
6 */
7
8#include <asm/ppc_asm.h>
9
10RELA = 7
11RELASZ = 8
12RELAENT = 9
13R_PPC64_RELATIVE = 22
14R_PPC64_UADDR64 = 43
15
16/*
17 * r3 = desired final address of kernel
18 */
19_GLOBAL(relocate)
20	mflr	r0
21	bcl	20,31,$+4
220:	mflr	r12		/* r12 has runtime addr of label 0 */
23	mtlr	r0
24	ld	r11,(p_dyn - 0b)(r12)
25	add	r11,r11,r12	/* r11 has runtime addr of .dynamic section */
26	ld	r9,(p_rela - 0b)(r12)
27	add	r9,r9,r12	/* r9 has runtime addr of .rela.dyn section */
28	ld	r10,(p_st - 0b)(r12)
29	add	r10,r10,r12	/* r10 has runtime addr of _stext */
30	ld	r13,(p_sym - 0b)(r12)
31	add	r13,r13,r12	/* r13 has runtime addr of .dynsym */
32
33	/*
34	 * Scan the dynamic section for the RELA, RELASZ and RELAENT entries.
35	 */
36	li	r7,0
37	li	r8,0
38.Ltags:
39	ld	r6,0(r11)	/* get tag */
40	cmpdi	r6,0
41	beq	.Lend_of_list		/* end of list */
42	cmpdi	r6,RELA
43	bne	2f
44	ld	r7,8(r11)	/* get RELA pointer in r7 */
45	b	4f
462:	cmpdi	r6,RELASZ
47	bne	3f
48	ld	r8,8(r11)	/* get RELASZ value in r8 */
49	b	4f
503:	cmpdi	r6,RELAENT
51	bne	4f
52	ld	r12,8(r11)	/* get RELAENT value in r12 */
534:	addi	r11,r11,16
54	b	.Ltags
55.Lend_of_list:
56	cmpdi	r7,0		/* check we have RELA, RELASZ, RELAENT */
57	cmpdi	cr1,r8,0
58	beq	.Lout
59	beq	cr1,.Lout
60	cmpdi	r12,0
61	beq	.Lout
62
63	/*
64	 * Work out linktime address of _stext and hence the
65	 * relocation offset to be applied.
66	 * cur_offset [r7] = rela.run [r9] - rela.link [r7]
67	 * _stext.link [r10] = _stext.run [r10] - cur_offset [r7]
68	 * final_offset [r3] = _stext.final [r3] - _stext.link [r10]
69	 */
70	subf	r7,r7,r9	/* cur_offset */
71	subf	r10,r7,r10
72	subf	r3,r10,r3	/* final_offset */
73
74	/*
75	 * Run through the list of relocations and process the
76	 * R_PPC64_RELATIVE and R_PPC64_UADDR64 ones.
77	 */
78	divd	r8,r8,r12	/* RELASZ / RELAENT */
79	mtctr	r8
80.Lrels:	ld	r0,8(r9)		/* ELF64_R_TYPE(reloc->r_info) */
81	cmpdi	r0,R_PPC64_RELATIVE
82	bne	.Luaddr64
83	ld	r6,0(r9)	/* reloc->r_offset */
84	ld	r0,16(r9)	/* reloc->r_addend */
85	b	.Lstore
86.Luaddr64:
87	srdi	r14,r0,32	/* ELF64_R_SYM(reloc->r_info) */
88	clrldi	r0,r0,32
89	cmpdi	r0,R_PPC64_UADDR64
90	bne	.Lnext
91	ld	r6,0(r9)
92	ld	r0,16(r9)
93	mulli	r14,r14,24	/* 24 == sizeof(elf64_sym) */
94	add	r14,r14,r13	/* elf64_sym[ELF64_R_SYM] */
95	ld	r14,8(r14)
96	add	r0,r0,r14
97.Lstore:
98	add	r0,r0,r3
99	stdx	r0,r7,r6
100.Lnext:
101	add	r9,r9,r12
102	bdnz	.Lrels
103.Lout:
104	blr
105
106.balign 8
107p_dyn:	.8byte	__dynamic_start - 0b
108p_rela:	.8byte	__rela_dyn_start - 0b
109p_sym:		.8byte __dynamic_symtab - 0b
110p_st:	.8byte	_stext - 0b
111
112