aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/image/relocate/head.S
blob: 3e5b374ba06dd3fdd5b483408bb37fbfb6d30f53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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)