mirror of
https://gitee.com/anod/open_agb_firm.git
synced 2025-05-06 22:04:10 +08:00
313 lines
9.4 KiB
ArmAsm
313 lines
9.4 KiB
ArmAsm
/*
|
|
* This file is part of open_agb_firm
|
|
* Copyright (C) 2021 derrek, profi200
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "asm_macros.h"
|
|
#include "arm.h"
|
|
#include "mem_map.h"
|
|
|
|
.syntax unified
|
|
.cpu arm946e-s
|
|
.fpu softvfp
|
|
|
|
.section .crt0, "ax", %progbits
|
|
|
|
|
|
|
|
BEGIN_ASM_FUNC _start no_section
|
|
msr cpsr_cxsf, #PSR_INT_OFF | PSR_SVC_MODE
|
|
|
|
@ Control register:
|
|
@ [19] ITCM load mode : disabled
|
|
@ [18] ITCM : disabled
|
|
@ [17] DTCM load mode : disabled
|
|
@ [16] DTCM : disabled
|
|
@ [15] Disable loading TBIT : disabled
|
|
@ [14] Round-robin replacement: disabled
|
|
@ [13] Vector select : 0xFFFF0000
|
|
@ [12] I-Cache : disabled
|
|
@ [7] Endianess : little
|
|
@ [2] D-Cache : disabled
|
|
@ [0] MPU : disabled
|
|
ldrh r3, =0x2078
|
|
mov r4, #0
|
|
mcr p15, 0, r3, c1, c0, 0 @ Write control register
|
|
mcr p15, 0, r4, c7, c5, 0 @ Invalidate I-Cache
|
|
mcr p15, 0, r4, c7, c6, 0 @ Invalidate D-Cache
|
|
mcr p15, 0, r4, c7, c10, 4 @ Drain write buffer
|
|
|
|
bl setupExceptionVectors @ Setup the vectors in ARM9 mem bootrom vectors jump to
|
|
bl setupTcms @ Setup and enable DTCM and ITCM
|
|
|
|
mov sp, #0 @ unused SVC mode sp
|
|
msr cpsr_cxsf, #PSR_INT_OFF | PSR_IRQ_MODE
|
|
ldr sp, =A9_IRQ_STACK_END
|
|
ldr r0, =A9_EXC_STACK_END
|
|
msr cpsr_cxsf, #PSR_INT_OFF | PSR_ABORT_MODE
|
|
mov sp, r0
|
|
msr cpsr_cxsf, #PSR_INT_OFF | PSR_UNDEF_MODE
|
|
mov sp, r0
|
|
msr cpsr_cxsf, #PSR_INT_OFF | PSR_SYS_MODE
|
|
ldr sp, =A9_STACK_END
|
|
|
|
bl setupMpu
|
|
|
|
@ Clear bss section
|
|
ldr r0, =__bss_start__
|
|
ldr r1, =__bss_end__
|
|
sub r2, r1, r0
|
|
mov r1, #0
|
|
bl clear32
|
|
@ Setup newlib heap
|
|
ldr r0, =IO_AHB_BASE @ CFG9 regs
|
|
ldr r1, [r0, #0xFFC] @ REG_CFG9_SOCINFO
|
|
tst r1, #2 @ Test for LGR1 bit (New 3DS prototype).
|
|
movne r2, #1
|
|
strne r2, [r0, #0x200] @ REG_CFG9_EXTMEMCNT9
|
|
ldr r0, =A9_HEAP_END
|
|
addne r0, #AHB_RAM_EXT_SIZE
|
|
ldr r1, =fake_heap_end
|
|
str r0, [r1]
|
|
blx __libc_init_array @ Initialize ctors and dtors
|
|
blx __systemInit
|
|
|
|
mov r0, #0 @ argc
|
|
adr r1, _dummyArgv @ argv
|
|
blx main
|
|
blx __systemDeinit
|
|
_start_lp:
|
|
mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
|
|
b _start_lp
|
|
|
|
.pool
|
|
_dummyArgv:
|
|
.4byte 0
|
|
END_ASM_FUNC
|
|
|
|
|
|
#define MAKE_BRANCH(src, dst) (0xEA000000 | (((((dst) - (src)) >> 2) - 2) & 0xFFFFFF))
|
|
|
|
BEGIN_ASM_FUNC setupExceptionVectors no_section
|
|
adr r0, _vectorStubs
|
|
ldr r1, =A9_VECTORS_START
|
|
ldmia r0!, {r2-r9}
|
|
stmia r1!, {r2-r9}
|
|
ldm r0, {r2-r5}
|
|
stm r1, {r2-r5}
|
|
bx lr
|
|
|
|
.pool
|
|
_vectorStubs:
|
|
ldr pc, irqHandlerPtr
|
|
irqHandlerPtr: .4byte irqHandler
|
|
udf #2
|
|
fiqHandlerPtr: .4byte (A9_VECTORS_START + 0x08)
|
|
udf #3
|
|
svcHandlerPtr: .4byte (A9_VECTORS_START + 0x10)
|
|
ldr pc, undefInstrHandlerPtr
|
|
undefInstrHandlerPtr: .4byte undefInstrHandler
|
|
ldr pc, prefetchAbortHandlerPtr
|
|
prefetchAbortHandlerPtr: .4byte prefetchAbortHandler
|
|
ldr pc, dataAbortHandlerPtr
|
|
dataAbortHandlerPtr: .4byte dataAbortHandler
|
|
END_ASM_FUNC
|
|
|
|
|
|
BEGIN_ASM_FUNC setupTcms no_section
|
|
ldr r1, =(ITCM_BASE | 0x24) @ Base = 0x00000000, size = 128 MiB (32 KiB mirrored)
|
|
ldr r0, =(DTCM_BASE | 0x0A) @ Base = 0xFFF00000, size = 16 KiB
|
|
mcr p15, 0, r0, c9, c1, 0 @ Write DTCM region reg
|
|
mcr p15, 0, r1, c9, c1, 1 @ Write ITCM region reg
|
|
mrc p15, 0, r0, c1, c0, 0 @ Read control register
|
|
orr r0, r0, #0x50000 @ Enable DTCM and ITCM
|
|
mcr p15, 0, r0, c1, c0, 0 @ Write control register
|
|
bx lr
|
|
|
|
.pool
|
|
END_ASM_FUNC
|
|
|
|
|
|
#define REGION_4KiB (0b01011)
|
|
#define REGION_8KiB (0b01100)
|
|
#define REGION_16KiB (0b01101)
|
|
#define REGION_32KiB (0b01110)
|
|
#define REGION_64KiB (0b01111)
|
|
#define REGION_128KiB (0b10000)
|
|
#define REGION_256KiB (0b10001)
|
|
#define REGION_512KiB (0b10010)
|
|
#define REGION_1MiB (0b10011)
|
|
#define REGION_2MiB (0b10100)
|
|
#define REGION_4MiB (0b10101)
|
|
#define REGION_8MiB (0b10110)
|
|
#define REGION_16MiB (0b10111)
|
|
#define REGION_32MiB (0b11000)
|
|
#define REGION_64MiB (0b11001)
|
|
#define REGION_128MiB (0b11010)
|
|
#define REGION_256MiB (0b11011)
|
|
#define REGION_512MiB (0b11100)
|
|
#define REGION_1GiB (0b11101)
|
|
#define REGION_2GiB (0b11110)
|
|
#define REGION_4GiB (0b11111)
|
|
#define MAKE_REGION(adr, size) ((adr) | ((size)<<1) | 1)
|
|
|
|
#define PER_NA (0)
|
|
#define PER_PRIV_RW_USR_NA (0b0001)
|
|
#define PER_PRIV_RW_USR_RO (0b0010)
|
|
#define PER_PRIV_RW_USR_RW (0b0011)
|
|
#define PER_PRIV_RO_USR_NA (0b0101)
|
|
#define PER_PRIV_RO_USR_RO (0b0110)
|
|
#define MAKE_PERMISSIONS(r0, r1, r2, r3, r4, r5, r6, r7) \
|
|
((r0) | (r1<<4) | (r2<<8) | (r3<<12) | (r4<<16) | (r5<<20) | (r6<<24) | (r7<<28))
|
|
|
|
BEGIN_ASM_FUNC setupMpu no_section
|
|
adr r0, _mpu_regions @ Table at end of file
|
|
ldm r0, {r1-r10}
|
|
mcr p15, 0, r1, c6, c0, 0 @ Write MPU region reg 0-7
|
|
mcr p15, 0, r2, c6, c1, 0
|
|
mcr p15, 0, r3, c6, c2, 0
|
|
mcr p15, 0, r4, c6, c3, 0
|
|
mcr p15, 0, r5, c6, c4, 0
|
|
mcr p15, 0, r6, c6, c5, 0
|
|
mcr p15, 0, r7, c6, c6, 0
|
|
mcr p15, 0, r8, c6, c7, 0
|
|
|
|
mcr p15, 0, r9, c5, c0, 2 @ Write data access permissions
|
|
mcr p15, 0, r10, c5, c0, 3 @ Write instruction access permissions
|
|
|
|
@ Data cachable bits:
|
|
@ Region 0 = no
|
|
@ Region 1 = yes
|
|
@ Region 2 = no <-- Never cache IO regs
|
|
@ Region 3 = yes
|
|
@ Region 4 = yes
|
|
@ Region 5 = no
|
|
@ Region 6 = no
|
|
@ Region 7 = yes
|
|
mov r0, #0b10011010
|
|
mcr p15, 0, r0, c2, c0, 0 @ Data cachable bits
|
|
|
|
@ Instruction cachable bits:
|
|
@ Region 0 = no
|
|
@ Region 1 = yes
|
|
@ Region 2 = no
|
|
@ Region 3 = no
|
|
@ Region 4 = no
|
|
@ Region 5 = no
|
|
@ Region 6 = no
|
|
@ Region 7 = yes
|
|
mov r1, #0b10000010
|
|
mcr p15, 0, r1, c2, c0, 1 @ Instruction cachable bits
|
|
|
|
@ Write bufferable bits:
|
|
@ Region 0 = no
|
|
@ Region 1 = yes
|
|
@ Region 2 = no <-- Never buffer IO regs
|
|
@ Region 3 = yes
|
|
@ Region 4 = yes
|
|
@ Region 5 = no
|
|
@ Region 6 = no
|
|
@ Region 7 = yes
|
|
@mov r2, #0b10011010 @ Same as data cachable bits
|
|
mcr p15, 0, r0, c3, c0, 0 @ Write bufferable bits
|
|
|
|
ldrh r1, =0x1005 @ MPU, D-Cache and I-Cache bitmask
|
|
mrc p15, 0, r0, c1, c0, 0 @ Read control register
|
|
orr r0, r0, r1 @ Enable MPU, D-Cache and I-Cache
|
|
mcr p15, 0, r0, c1, c0, 0 @ Write control register
|
|
bx lr
|
|
|
|
.pool
|
|
_mpu_regions:
|
|
@ Region 0: ITCM kernel mirror 32 KiB
|
|
@ Region 1: ARM9 internal mem + N3DS extension 2 MiB
|
|
@ Region 2: IO region 2 MiB covers only ARM9 accessible regs
|
|
@ Region 3: VRAM 8 MiB
|
|
@ Region 4: DSP mem and AXIWRAM 1 MiB
|
|
@ Region 5: FCRAM + N3DS extension 256 MiB
|
|
@ Region 6: DTCM 16 KiB
|
|
@ Region 7: Exception vectors + ARM9 bootrom 64 KiB
|
|
.4byte MAKE_REGION(ITCM_KERN9_MIRROR, REGION_32KiB)
|
|
.4byte MAKE_REGION(AHB_RAM_BASE, REGION_2MiB)
|
|
.4byte MAKE_REGION(IO_AHB_BASE, REGION_2MiB)
|
|
.4byte MAKE_REGION(VRAM_BASE, REGION_8MiB)
|
|
.4byte MAKE_REGION(DSP_RAM_BASE, REGION_1MiB)
|
|
.4byte MAKE_REGION(FCRAM_BASE, REGION_256MiB)
|
|
.4byte MAKE_REGION(DTCM_BASE, REGION_16KiB)
|
|
.4byte MAKE_REGION(BOOT9_BASE, REGION_64KiB)
|
|
_mpu_permissions:
|
|
@ Data access permissions:
|
|
@ Region 0: User = --, Privileged = RW
|
|
@ Region 1: User = --, Privileged = RW
|
|
@ Region 2: User = --, Privileged = RW
|
|
@ Region 3: User = --, Privileged = RW
|
|
@ Region 4: User = --, Privileged = RW
|
|
@ Region 5: User = --, Privileged = RW
|
|
@ Region 6: User = --, Privileged = RW
|
|
@ Region 7: User = --, Privileged = RO
|
|
.4byte MAKE_PERMISSIONS(PER_PRIV_RW_USR_NA, PER_PRIV_RW_USR_NA,
|
|
PER_PRIV_RW_USR_NA, PER_PRIV_RW_USR_NA,
|
|
PER_PRIV_RW_USR_NA, PER_PRIV_RW_USR_NA,
|
|
PER_PRIV_RW_USR_NA, PER_PRIV_RO_USR_NA)
|
|
@ Instruction access permissions:
|
|
@ Region 0: User = --, Privileged = RO
|
|
@ Region 1: User = --, Privileged = RO
|
|
@ Region 2: User = --, Privileged = --
|
|
@ Region 3: User = --, Privileged = --
|
|
@ Region 4: User = --, Privileged = --
|
|
@ Region 5: User = --, Privileged = --
|
|
@ Region 6: User = --, Privileged = --
|
|
@ Region 7: User = --, Privileged = RO
|
|
.4byte MAKE_PERMISSIONS(PER_PRIV_RO_USR_NA, PER_PRIV_RO_USR_NA,
|
|
PER_NA, PER_NA,
|
|
PER_NA, PER_NA,
|
|
PER_NA, PER_PRIV_RO_USR_NA)
|
|
END_ASM_FUNC
|
|
|
|
|
|
@ Needed by libc
|
|
BEGIN_ASM_FUNC _init no_section thumb
|
|
bx lr
|
|
END_ASM_FUNC
|
|
|
|
|
|
BEGIN_ASM_FUNC deinitCpu no_section
|
|
mov r3, lr
|
|
|
|
msr cpsr_cxsf, #PSR_INT_OFF | PSR_SYS_MODE
|
|
@ Stub vectors to endless loops
|
|
ldr r0, =AHB_RAM_BASE
|
|
ldr r2, =MAKE_BRANCH(0, 0) @ Endless loop
|
|
mov r1, #6
|
|
deinitCpu_lp:
|
|
str r2, [r0], #8
|
|
subs r1, r1, #1
|
|
bne deinitCpu_lp
|
|
|
|
bl cleanDCache
|
|
mov r2, #0
|
|
ldrh r1, =0x1005 @ MPU, D-Cache and I-Cache bitmask
|
|
mrc p15, 0, r0, c1, c0, 0 @ Read control register
|
|
bic r0, r0, r1 @ Disable MPU, D-Cache and I-Cache
|
|
mcr p15, 0, r0, c1, c0, 0 @ Write control register
|
|
mcr p15, 0, r2, c7, c5, 0 @ Invalidate I-Cache
|
|
mcr p15, 0, r2, c7, c6, 0 @ Invalidate D-Cache
|
|
mcr p15, 0, r2, c7, c10, 4 @ Drain write buffer
|
|
bx r3
|
|
|
|
.pool
|
|
END_ASM_FUNC
|