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@xxxxxxxxxxx> --- arch/mips/kernel/head.S | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) 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@xxxxxxxx and Carsten Langgaard, carstenl@xxxxxxxx * 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 -- 2.1.0