99 lines
3.2 KiB
ArmAsm
99 lines
3.2 KiB
ArmAsm
|
#include "mips.h"
|
||
|
|
||
|
.extern main
|
||
|
.global start
|
||
|
|
||
|
.set mips32
|
||
|
.set noreorder
|
||
|
.set noat
|
||
|
|
||
|
.section .init.text,"ax",%progbits
|
||
|
/* WARNING
|
||
|
* We have no idea where the stubs starts running, there basically are three cases:
|
||
|
* - tcsm0: the stub is already at the right place, nothing do to
|
||
|
* - ram: sdram/ddram is active and we just need to move the stub
|
||
|
* - cache: the bootrom put us in cache-as-ram, we need to be careful
|
||
|
* Note that that those are initially quite different because:
|
||
|
* - tcsm0 is uncached
|
||
|
* - ram is almost always cached when we are running from it
|
||
|
* - cache-as-ram is cached but the cache is the only copy of our code and the
|
||
|
* icache was prefilled from dcache by the bootrom using some mips magic
|
||
|
*
|
||
|
* This means we have to be very careful with the cache because if we flush the
|
||
|
* icache in the cache-as-cache case, we cannot refill it, and worse, we cannot
|
||
|
* commit the dcache either because the ram might not even be initialised. Thus
|
||
|
* the only safe option in all cases is to copy the stub to an *uncached* location
|
||
|
* so that we don't have to commit the dcache and the icache can safely read from
|
||
|
* it.
|
||
|
*/
|
||
|
start:
|
||
|
bltzal zero, load_addr /* ra = PC + 8, branch not taken */
|
||
|
nop
|
||
|
load_addr:
|
||
|
addiu v0, ra, -8 /* calc real load address
|
||
|
account for branch delay slot */
|
||
|
move k0, v0 /* store starting location to give it to main */
|
||
|
|
||
|
la t0, relocstart /* relocate code if needed */
|
||
|
la t1, relocend
|
||
|
beq t0, v0, clear_bss /* no relocation needed */
|
||
|
nop
|
||
|
reloc_loop:
|
||
|
lw s0, 0(v0) /* v0 = src */
|
||
|
lw s1, 4(v0)
|
||
|
lw s2, 8(v0)
|
||
|
lw s3, 12(v0)
|
||
|
|
||
|
sw s0, 0(t0) /* t0 = dst */
|
||
|
sw s1, 4(t0)
|
||
|
sw s2, 8(t0)
|
||
|
sw s3, 12(t0)
|
||
|
|
||
|
/* Tricky part: as explained earlier, tcsm0 is uncached so no need to commit
|
||
|
* the dcache but we want to invalidate the icache ONLY AT THIS LOCATION.
|
||
|
* Indeed, if the invalidate the entire icache in the cache-as-ram case, we
|
||
|
* will miserably crash */
|
||
|
cache ICHitInv, 0(t0) /* invalidate virtual address in icache */
|
||
|
|
||
|
addiu t0, t0, 16 /* inc dst addr */
|
||
|
slt t2, t0, t1
|
||
|
bnez t2, reloc_loop
|
||
|
addiu v0, v0, 16 /* inc src addr */
|
||
|
|
||
|
/* jump to tcsm0 */
|
||
|
la t0, tcsm0_entry
|
||
|
jr t0
|
||
|
sync
|
||
|
tcsm0_entry:
|
||
|
/* now that we are running from tcsm0, which is uncached, we can finally
|
||
|
* properly invalidate all caches just to be sure */
|
||
|
mtc0 zero, C0_TagLo
|
||
|
mtc0 zero, C0_DataLo
|
||
|
la t0, 0x80000000 /* an idx op should use an unmappable address */
|
||
|
ori t1, t0, 0x4000 /* 16kB cache */
|
||
|
|
||
|
cache_inv_loop:
|
||
|
cache ICIndexStTag, 0(t0) /* index store icache tag */
|
||
|
cache DCIndexStTag, 0(t0) /* index store dcache tag */
|
||
|
bne t0, t1, cache_inv_loop
|
||
|
addiu t0, 0x20 /* 32 bytes per line */
|
||
|
|
||
|
clear_bss:
|
||
|
la t0, bssbegin
|
||
|
la t1, bssend
|
||
|
beq t0, t1, stack_setup
|
||
|
nop
|
||
|
|
||
|
clear_bss_loop:
|
||
|
sw zero, 0(t0)
|
||
|
bne t0, t1, clear_bss_loop
|
||
|
addiu t0, 4
|
||
|
|
||
|
stack_setup:
|
||
|
la sp, oc_stackend
|
||
|
|
||
|
/* jump to C code */
|
||
|
la t0, main
|
||
|
jr t0
|
||
|
move a0, k0
|