diff mbox series

[RFC,3/3] MIPS: relocate: Add support to relocate kernel auto

Message ID 1617283633-18598-4-git-send-email-hejinyang@loongson.cn (mailing list archive)
State Superseded
Headers show
Series [RFC,1/3] MIPS: relocate: Only compile relocs when CONFIG_RELOCATABLE is enabled | expand

Commit Message

Jinyang He April 1, 2021, 1:27 p.m. UTC
These asm code is based on relocate.c. And in this stage,
only do relocate for _text and ex_table.

Signed-off-by: Jinyang He <hejinyang@loongson.cn>
---
 arch/mips/kernel/head.S | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 149 insertions(+)
diff mbox series

Patch

diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index a25af1d..dc59b11 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -13,6 +13,7 @@ 
  * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
  */
+
 #include <linux/init.h>
 #include <linux/threads.h>
 
@@ -26,6 +27,152 @@ 
 
 #include <kernel-entry-init.h>
 
+	.macro	do_relocate_kernel
+	.set	push
+#ifdef CONFIG_RELOCATABLE
+#define R_MIPS_32	2
+#define R_MIPS_26	4
+#define R_MIPS_HI16	5
+#define R_MIPS_64	18
+	/* Save args */
+	move s0, a0
+	move s1, a1
+	move s2, a2
+	move s3, a3
+
+	/* Whether the PC meets expectation */
+	bal	1f
+1:	move	a0, ra
+	PTR_LA	a1, 1b
+	PTR_SUB	a0, a0, a1
+	beqz	a0, 999f
+
+	/* Whether offset 64KB aligned */
+	and		t0, a0, 0xffff
+	bnez	t0, 999f
+
+	/* Whether current _text and _end are in the PC region */
+	PTR_LA	t0, _end
+	PTR_ADDU	t1, t0, a0
+	PTR_SRL	t1, 28
+	PTR_SRL	t0, 28
+	bne	t0, t1, 999f
+
+	PTR_LA	t0, _text
+	PTR_ADDU	t1, t0, a0
+	move	a3, t1
+	PTR_SRL	t1, 28
+	PTR_SRL	t0, 28
+	bne	t0, t1, 999f
+
+	/* get current __start/stop___ex_table address */
+	PTR_LA	a1, __start___ex_table
+	PTR_ADDU	a1, a0
+	PTR_LA	a2, __stop___ex_table
+	PTR_ADDU	a2, a0
+
+	/*
+	 * a0: offset
+	 * a1: current __start___ex_table
+	 * a2: current __stop___ex_table
+	 */
+1:	beq	a1, a2, 998f
+	PTR_L	t0, 0(a1)
+	PTR_ADDU	t0, a0
+	PTR_S	t0, 0(a1)
+	LONG_ADDIU	a1, PTRSIZE
+	b	1b
+
+998:
+	/* get current _relocation_start address */
+	PTR_LA	a1, _relocation_start
+	PTR_ADDU	a1, a0
+
+	/*
+	 * a0: offset
+	 * a1: _relocation_start[]
+	 * a2: offset >> 16, to relocate R_MIPS_HI16
+	 * a3: current _text
+	 * t0: to load _relocation_start[]
+	 * t1: relocation type
+	 * t2: current relocate position
+	 * t3: temporarily
+	 * t8: 0x00ffffff, mask, to get relocate position
+	 * t9: offset >> 2, to relocate R_MIPS_26
+	 */
+	li	t8, 0x00ffffff
+	LONG_SRL t9, a0, 2
+	LONG_SRL a2, a0, 16
+1:	lw	t0, 0(a1)
+	beqz	t0, 900f
+	LONG_SRL	t1, t0, 24
+	and	t1, 0xff
+	and	t2, t0, t8
+	LONG_SLL	t2, 2
+	PTR_ADDU	t2, a3
+
+	li	t3, R_MIPS_64
+	beq	t1, t3, 964f
+	li	t3, R_MIPS_32
+	beq	t1, t3, 932f
+	li	t3, R_MIPS_26
+	beq	t1, t3, 926f
+	li	t3, R_MIPS_HI16
+	beq	t1, t3, 916f
+	b	999f
+
+964:
+#ifdef CONFIG_64BIT
+	ld	t3, 0(t2)
+	LONG_ADDU	t3, a0
+	sd	t3, 0(t2)
+#endif
+	LONG_ADDIU	a1, 4
+	b	1b
+
+932:
+	lw	t3, 0(t2)
+	LONG_ADDU	t3, a0
+	sw	t3, 0(t2)
+	LONG_ADDIU	a1, 4
+	b	1b
+
+926:
+	lw	t3, 0(t2)
+	LONG_ADDU	t3, t9
+	sw	t3, 0(t2)
+	LONG_ADDIU	a1, 4
+	b	1b
+
+916:
+	lw	t3, 0(t2)
+	LONG_ADDU	t3, a2
+	sw	t3, 0(t2)
+	LONG_ADDIU	a1, 4
+	b	1b
+
+900:
+	/* Complete! And flush i-cache */
+	PTR_LA	a0, _text
+	PTR_LA	a1,	_end
+	synci	0(a0)
+	rdhwr	t0, $1
+	beqz	t0, 999f
+	PTR_ADDU	a0, t0
+	PTR_SUBU	t0, a1, a0
+	bgtz	t0, 900b
+	sync
+
+999:
+	/* Restore args */
+	move a0, s0
+	move a1, s1
+	move a2, s2
+	move a3, s3
+#endif /* CONFIG_RELOCATABLE */
+	.set	pop
+	.endm
+
 	/*
 	 * For the moment disable interrupts, mark the kernel mode and
 	 * set ST0_KX so that the CPU does not spit fire when using
@@ -83,6 +230,8 @@  FEXPORT(__kernel_entry)
 
 NESTED(kernel_entry, 16, sp)			# kernel entry point
 
+	do_relocate_kernel
+
 	kernel_entry_setup			# cpu specific setup
 
 	setup_c0_status_pri