ramips: move relocating loader to common location
[openwrt/svn-archive/archive.git] / target / linux / generic / image / relocate / head.S
diff --git a/target/linux/generic/image/relocate/head.S b/target/linux/generic/image/relocate/head.S
new file mode 100644 (file)
index 0000000..3e5b374
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Kernel relocation stub for MIPS devices
+ *
+ * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Based on:
+ *
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Some parts of this code was based on the OpenWrt specific lzma-loader
+ * for the BCM47xx and ADM5120 based boards:
+ *     Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
+ *     Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include "cp0regdef.h"
+#include "cacheops.h"
+
+#define KSEG0          0x80000000
+
+       .macro  ehb
+       sll     zero, 3
+       .endm
+
+       .macro reset
+       li t0, 0xbe000034
+       lw t1, 0(t0)
+       ori t1, 1
+       sw t1, 0(t0)
+       .endm
+
+       .text
+
+LEAF(startup)
+       .set noreorder
+       .set mips32
+
+       .fill 0x10000
+
+       mtc0    zero, CP0_WATCHLO       # clear watch registers
+       mtc0    zero, CP0_WATCHHI
+       mtc0    zero, CP0_CAUSE         # clear before writing status register
+
+       mfc0    t0, CP0_STATUS
+       li      t1, 0x1000001f
+       or      t0, t1
+       xori    t0, 0x1f
+       mtc0    t0, CP0_STATUS
+       ehb
+
+       mtc0    zero, CP0_COUNT
+       mtc0    zero, CP0_COMPARE
+       ehb
+
+       la      t0, __reloc_label       # get linked address of label
+       bal     __reloc_label           # branch and link to label to
+       nop                             # get actual address
+__reloc_label:
+       subu    t0, ra, t0              # get reloc_delta
+
+       /* Copy our code to the right place */
+       la      t1, _code_start         # get linked address of _code_start
+       la      t2, _code_end           # get linked address of _code_end
+
+       addu    t4, t2, t0              # calculate actual address of _code_end
+       lw      t5, 0(t4)               # get extra data size
+
+       add     t2, t5
+       add     t2, 4
+
+       add     t0, t1                  # calculate actual address of _code_start
+
+__reloc_copy:
+       lw      t3, 0(t0)
+       sw      t3, 0(t1)
+       add     t1, 4
+       blt     t1, t2, __reloc_copy
+       add     t0, 4
+
+       /* flush cache */
+       la      t0, _code_start
+       la      t1, _code_end
+
+       li      t2, ~(CONFIG_CACHELINE_SIZE - 1)
+       and     t0, t2
+       and     t1, t2
+       li      t2, CONFIG_CACHELINE_SIZE
+
+       b       __flush_check
+       nop
+
+__flush_line:
+       cache   Hit_Writeback_Inv_D, 0(t0)
+       cache   Hit_Invalidate_I, 0(t0)
+       add     t0, t2
+
+__flush_check:
+       bne     t0, t1, __flush_line
+       nop
+
+       sync
+
+       la      t0, __reloc_back
+       j       t0
+       nop
+
+__reloc_back:
+       la      t0, _code_end
+       add     t0, 4
+
+       addu    t1, t0, t5
+
+       li      t2, KERNEL_ADDR
+
+__kernel_copy:
+       lw      t3, 0(t0)
+       sw      t3, 0(t2)
+       add     t0, 4
+       blt     t0, t1, __kernel_copy
+       add     t2, 4
+
+       /* flush cache */
+       li      t0, KERNEL_ADDR
+       addu    t1, t0, t5
+
+       add t1, CONFIG_CACHELINE_SIZE - 1
+       li      t2, ~(CONFIG_CACHELINE_SIZE - 1)
+       and     t0, t2
+       and     t1, t2
+       li      t2, CONFIG_CACHELINE_SIZE
+
+       b       __kernel_flush_check
+       nop
+
+__kernel_flush_line:
+       cache   Hit_Writeback_Inv_D, 0(t0)
+       cache   Hit_Invalidate_I, 0(t0)
+       add     t0, t2
+
+__kernel_flush_check:
+       bne     t0, t1, __kernel_flush_line
+       nop
+
+       sync
+
+       li      t0, KERNEL_ADDR
+       jr      t0
+       nop
+
+       .set reorder
+END(startup)