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 <[email protected]>
---
 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, [email protected] and Carsten Langgaard, [email protected]
  * 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

Reply via email to