summaryrefslogtreecommitdiff
path: root/utils/hwstub/stub/jz4760b/crt0.S
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hwstub/stub/jz4760b/crt0.S')
-rw-r--r--utils/hwstub/stub/jz4760b/crt0.S98
1 files changed, 98 insertions, 0 deletions
diff --git a/utils/hwstub/stub/jz4760b/crt0.S b/utils/hwstub/stub/jz4760b/crt0.S
new file mode 100644
index 0000000000..73dbe20428
--- /dev/null
+++ b/utils/hwstub/stub/jz4760b/crt0.S
@@ -0,0 +1,98 @@
1#include "mips.h"
2
3.extern main
4.global start
5
6.set mips32
7.set noreorder
8.set noat
9
10.section .init.text,"ax",%progbits
11/* WARNING
12 * We have no idea where the stubs starts running, there basically are three cases:
13 * - tcsm0: the stub is already at the right place, nothing do to
14 * - ram: sdram/ddram is active and we just need to move the stub
15 * - cache: the bootrom put us in cache-as-ram, we need to be careful
16 * Note that that those are initially quite different because:
17 * - tcsm0 is uncached
18 * - ram is almost always cached when we are running from it
19 * - cache-as-ram is cached but the cache is the only copy of our code and the
20 * icache was prefilled from dcache by the bootrom using some mips magic
21 *
22 * This means we have to be very careful with the cache because if we flush the
23 * icache in the cache-as-cache case, we cannot refill it, and worse, we cannot
24 * commit the dcache either because the ram might not even be initialised. Thus
25 * the only safe option in all cases is to copy the stub to an *uncached* location
26 * so that we don't have to commit the dcache and the icache can safely read from
27 * it.
28 */
29start:
30 bltzal zero, load_addr /* ra = PC + 8, branch not taken */
31 nop
32load_addr:
33 addiu v0, ra, -8 /* calc real load address
34 account for branch delay slot */
35 move k0, v0 /* store starting location to give it to main */
36
37 la t0, relocstart /* relocate code if needed */
38 la t1, relocend
39 beq t0, v0, clear_bss /* no relocation needed */
40 nop
41reloc_loop:
42 lw s0, 0(v0) /* v0 = src */
43 lw s1, 4(v0)
44 lw s2, 8(v0)
45 lw s3, 12(v0)
46
47 sw s0, 0(t0) /* t0 = dst */
48 sw s1, 4(t0)
49 sw s2, 8(t0)
50 sw s3, 12(t0)
51
52 /* Tricky part: as explained earlier, tcsm0 is uncached so no need to commit
53 * the dcache but we want to invalidate the icache ONLY AT THIS LOCATION.
54 * Indeed, if the invalidate the entire icache in the cache-as-ram case, we
55 * will miserably crash */
56 cache ICHitInv, 0(t0) /* invalidate virtual address in icache */
57
58 addiu t0, t0, 16 /* inc dst addr */
59 slt t2, t0, t1
60 bnez t2, reloc_loop
61 addiu v0, v0, 16 /* inc src addr */
62
63 /* jump to tcsm0 */
64 la t0, tcsm0_entry
65 jr t0
66 sync
67tcsm0_entry:
68 /* now that we are running from tcsm0, which is uncached, we can finally
69 * properly invalidate all caches just to be sure */
70 mtc0 zero, C0_TagLo
71 mtc0 zero, C0_DataLo
72 la t0, 0x80000000 /* an idx op should use an unmappable address */
73 ori t1, t0, 0x4000 /* 16kB cache */
74
75cache_inv_loop:
76 cache ICIndexStTag, 0(t0) /* index store icache tag */
77 cache DCIndexStTag, 0(t0) /* index store dcache tag */
78 bne t0, t1, cache_inv_loop
79 addiu t0, 0x20 /* 32 bytes per line */
80
81clear_bss:
82 la t0, bssbegin
83 la t1, bssend
84 beq t0, t1, stack_setup
85 nop
86
87clear_bss_loop:
88 sw zero, 0(t0)
89 bne t0, t1, clear_bss_loop
90 addiu t0, 4
91
92stack_setup:
93 la sp, oc_stackend
94
95 /* jump to C code */
96 la t0, main
97 jr t0
98 move a0, k0