-.section .text.start
.align 4
.global _start
+.section .text.start, "x"
_start:
ldr r2, =argc
str r0, [r2]
ldr r2, =argv
str r1, [r2]
- b mpu
+ b init
argc: .int 0x00000000
argv: .int 0x00000000
-mpu:
- // Change the stack pointer
- mov sp, #0x27000000
-
- // Disable caches / mpu
- mrc p15, 0, r4, c1, c0, 0 // read control register
- bic r4, #(1<<12) // - instruction cache disable
- bic r4, #(1<<2) // - data cache disable
- bic r4, #(1<<0) // - mpu disable
- mcr p15, 0, r4, c1, c0, 0 // write control register
-
- // Give read/write access to all the memory regions
- ldr r5, =0x33333333
- mcr p15, 0, r5, c5, c0, 2 // write data access
- mcr p15, 0, r5, c5, c0, 3 // write instruction access
-
- // Sets MPU permissions and cache settings
- ldr r0, =0xFFFF001D // ffff0000 32k
- ldr r1, =0x01FF801D // 01ff8000 32k
- ldr r2, =0x08000027 // 08000000 1M
- ldr r3, =0x10000021 // 10000000 128k
- ldr r4, =0x10100025 // 10100000 512k
- ldr r5, =0x20000035 // 20000000 128M
- ldr r6, =0x1FF00027 // 1FF00000 1M
- ldr r7, =0x1800002D // 18000000 8M
- mov r10, #0x25
- mov r11, #0x25
- mov r12, #0x25
- mcr p15, 0, r0, c6, c0, 0
- mcr p15, 0, r1, c6, c1, 0
- mcr p15, 0, r2, c6, c2, 0
- mcr p15, 0, r3, c6, c3, 0
- mcr p15, 0, r4, c6, c4, 0
- mcr p15, 0, r5, c6, c5, 0
- mcr p15, 0, r6, c6, c6, 0
- mcr p15, 0, r7, c6, c7, 0
- mcr p15, 0, r10, c3, c0, 0 // Write bufferable 0, 2, 5
- mcr p15, 0, r11, c2, c0, 0 // Data cacheable 0, 2, 5
- mcr p15, 0, r12, c2, c0, 1 // Inst cacheable 0, 2, 5
-
- // Enable caches
- mrc p15, 0, r4, c1, c0, 0 // read control register
- orr r4, r4, #(1<<18) // - itcm enable
- orr r4, r4, #(1<<12) // - instruction cache enable
- orr r4, r4, #(1<<2) // - data cache enable
- orr r4, r4, #(1<<0) // - mpu enable
- mcr p15, 0, r4, c1, c0, 0 // write control register
-
- // Flush caches
- mov r5, #0
- mcr p15, 0, r5, c7, c5, 0 // flush I-cache
- mcr p15, 0, r5, c7, c6, 0 // flush D-cache
- mcr p15, 0, r5, c7, c10, 4 // drain write buffer
-
- // Fixes mounting of SDMC
+init:
+ // Disable IRQ
+ mrs r0, cpsr
+ orr r0, r0, #0x80
+ msr cpsr_c, r0
+
+ // Flush caches, make sure to sync memory with what's on the cache before
+ // turning off the MPU
+ adr r0, flush_all_caches_offset
+ ldr r1, [r0]
+ add r0, r1, r0
+ blx r0
+
+ // Disable caches and MPU
+ adr r0, disable_mpu_and_caching_offset
+ ldr r1, [r0]
+ add r0, r1, r0
+ blx r0
+
+ // Flush caches, for good measure. Makes sure there is nothing in the caches
+ // when the MPU is brought back online.
+ adr r0, flush_all_caches_offset
+ ldr r1, [r0]
+ add r0, r1, r0
+ blx r0
+
+ // FIXME should we attempt to save the last stack?
+ // Setup stacks
+ adr r0, setup_stacks_offset
+ ldr r1, [r0]
+ add r0, r1, r0
+ blx r0
+
+ // Switch to system mode
+ mrs r0, cpsr
+ orr r1, r0, #0x1F
+ msr cpsr_c, r1
+
+ // Change the stack pointer
+ ldr sp, =0x27F00000
+
+ // make sure ITCM is accessible
+ mrc p15, 0, r0, c1, c0, 0
+ orr r0, r0, #(1<<18)
+ mcr p15, 0, r0, c1, c0, 0
+
+ // clear bss
+ adr r0, clear_bss_offset
+ ldr r1, [r0]
+ add r0, r1, r0
+ blx r0
+
+ // Give read/write access to all the memory regions
+ ldr r0, =0x33333333
+ mcr p15, 0, r0, c5, c0, 2 // write data access
+ mcr p15, 0, r0, c5, c0, 3 // write instruction access
+
+ // Set MPU permissions and cache settings
+ ldr r0, =0xFFFF001D // ffff0000 32k | bootrom unprotected
+ ldr r1, =0x3000801B // 30000000 16k | dtcm
+ ldr r2, =0x00000035 // 00000000 128MB | itcm
+ ldr r3, =0x08000029 // 08000000 2M | arm9 mem
+ ldr r4, =0x10000029 // 10000000 2M | io mem
+ ldr r5, =0x20000037 // 20000000 256M | fcram
+ ldr r6, =0x1FF00027 // 1FF00000 1M
+ ldr r7, =0x1800002D // 18000000 8M
+ mcr p15, 0, r0, c6, c0, 0
+ mcr p15, 0, r1, c6, c1, 0
+ mcr p15, 0, r2, c6, c2, 0
+ mcr p15, 0, r3, c6, c3, 0
+ mcr p15, 0, r4, c6, c4, 0
+ mcr p15, 0, r5, c6, c5, 0
+ mcr p15, 0, r6, c6, c6, 0
+ mcr p15, 0, r7, c6, c7, 0
+ mov r0, #0xA5 // FIXME which sections does this do... stuff to?
+ mcr p15, 0, r0, c2, c0, 0 // data cacheable
+ mcr p15, 0, r0, c2, c0, 1 // instruction cacheable
+ mcr p15, 0, r0, c3, c0, 0 // data bufferable
+
+ // Enable caches and MPU
+ adr r0, enable_mpu_and_caching_offset
+ ldr r1, [r0]
+ add r0, r1, r0
+ blx r0
+
+ // Fix mounting of SDMC
ldr r0, =0x10000020
mov r1, #0x340
str r1, [r0]
+ // Reload argc and argv.
ldr r0, argc
ldr r1, argv
- bl main
+ // Launch main(argc, argv)
+ adr r2, main_offset
+ ldr r3, [r2]
+ add r2, r3, r2
+ blx r2
+ bx lr
+
+ die:
+ b die //if we return, just forcibly hang (should we attempt to call the rest vector???)
+
+disable_mpu_and_caching_offset:
+.word disable_mpu_and_caching-.
+
+enable_mpu_and_caching_offset:
+.word enable_mpu_and_caching-.
+
+relocate_section_offset:
+.word relocate_section-.
+
+flush_all_caches_offset:
+.word flush_all_caches-.
+
+setup_stacks_offset:
+.word setup_stacks-.
+
+__bss_start_offset:
+.word __bss_start-.
+
+__bss_end_offset:
+.word __bss_end-.
+
+clear_bss_offset:
+.word clear_bss-.
+
+main_offset:
+.word main-.
+
+clear_bss:
+ //clear bss
+ adr r0, __bss_start_offset
+ ldr r1, [r0]
+ add r0, r1, r0
+
+ adr r1, __bss_end_offset
+ ldr r2, [r1]
+ add r1, r2, r1
+ mov r2, #0
+ .Lclear_bss_loop:
+ cmp r0, r1
+ beq .Lclear_bss_loop_done
+ str r2, [r0], #4
+ b .Lclear_bss_loop
+ .Lclear_bss_loop_done:
+ blx lr
+
+setup_stacks:
+ // Set up the stacks for all CPU modes
+ // start by clearing mode bits
+ mrs r0, cpsr
+ mov r2, r0 // preserve current mode
+ bic r0, r0, #0x1F
+
+ // System mode
+ orr r1, r0, #0x1F
+ msr cpsr_c, r1
+ ldr sp, =0x8000
+
+ // Abort mode
+ orr r1, r0, #0x17
+ msr cpsr_c, r1
+ ldr sp, =0x8000
+
+ // IRQ mode
+ orr r1, r0, #0x12
+ msr cpsr_c, r1
+ ldr sp, =0x8000
+
+ // FIQ mode
+ orr r1, r0, #0x11
+ msr cpsr_c, r1
+ ldr sp, =0x8000
+
+ // Supervisor mode
+ orr r1, r0, #0x13
+ msr cpsr_c, r1
+ ldr sp, =0x8000
+
+ // Restore prvious mode
+ msr cpsr_c, r2
+
+ blx lr
+
+disable_mpu_and_caching:
+ // Disable caches and MPU
+ mrc p15, 0, r0, c1, c0, 0 // read control register
+ bic r0, r0, #(1<<12) // - instruction cache enable
+ bic r0, r0, #(1<<2) // - data cache enable
+ bic r0, r0, #(1<<0) // - mpu enable
+ mcr p15, 0, r0, c1, c0, 0 // write control register
+
+ bx lr
+
+enable_mpu_and_caching:
+ // Enable caches and MPU
+ mrc p15, 0, r0, c1, c0, 0 // read control register
+ orr r0, r0, #(1<<12) // - instruction cache enable
+ orr r0, r0, #(1<<2) // - data cache enable
+ orr r0, r0, #(1<<0) // - mpu enable
+ mcr p15, 0, r0, c1, c0, 0 // write control register
+
+ bx lr
+
+// r0 - region start
+// r1 - region end
+// r2 - relocation base (usually starting PC address)
+relocate_section:
+
+ adr r2, relocation_base_offset
+ ldr r3, [r2]
+ add r2, r3, r2
+
+ .Lreloc_init:
+ cmp r0, r1
+ beq .Lrelocinit_done
+ ldr r3, [r0]
+ add r3, r2, r3
+ str r3, [r0], #4
+ b .Lreloc_init
+ .Lrelocinit_done:
+
+ bx lr
+
+relocation_base_offset:
+.word _start-.
+
+flush_all_caches:
+
+ // flush instruction cache, it's not flushed by Nintendo's function
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0
+
+ // Nintendo's function uses r0-r2, r12, all registers that don't need
+ // to be saved, just be aware that they are changed
+ // use Nintendo's bx lr to return
+ ldr r0, =0xFFFF0830 // Nintendo's flush function in unprot. bootrom
+ bx r0
-.die:
- b .die