diff options
Diffstat (limited to 'utils/hwstub/stub/jz4760b/crt0.S')
-rw-r--r-- | utils/hwstub/stub/jz4760b/crt0.S | 98 |
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 | */ | ||
29 | start: | ||
30 | bltzal zero, load_addr /* ra = PC + 8, branch not taken */ | ||
31 | nop | ||
32 | load_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 | ||
41 | reloc_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 | ||
67 | tcsm0_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 | |||
75 | cache_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 | |||
81 | clear_bss: | ||
82 | la t0, bssbegin | ||
83 | la t1, bssend | ||
84 | beq t0, t1, stack_setup | ||
85 | nop | ||
86 | |||
87 | clear_bss_loop: | ||
88 | sw zero, 0(t0) | ||
89 | bne t0, t1, clear_bss_loop | ||
90 | addiu t0, 4 | ||
91 | |||
92 | stack_setup: | ||
93 | la sp, oc_stackend | ||
94 | |||
95 | /* jump to C code */ | ||
96 | la t0, main | ||
97 | jr t0 | ||
98 | move a0, k0 | ||