#include <machine/asm.h>
#include <arm/armreg.h>
#include <arm/arm32/pte.h>
.section .start,"ax",%progbits
.global _C_LABEL(beast_start)
_C_LABEL(beast_start):
/*
* We will go ahead and disable the MMU here so that we don't
* have to worry about flushing caches, etc.
*
* Note that we may not currently be running VA==PA, which means
* we'll need to leap to the next insn after disabing the MMU.
*/
/* ADR is a pseudo instruction - LDR Rx, =label
* Load unmapped label address into R8 register
*
*/
adr r8, Lunmapped
/* BIC - bit clear instruction
* BIC{<cond>}{S} <Rd> <Rn> <shifter_operand>
* Bitwise AND of <Rn> with complement of value of <shifter_operand>
* Stores ther result in <Rd>
*
* R8 = (R8) AND ~(0xff000000)
*/
bic r8, r8, #0xff000000 /* clear upper 8 bits */
/*
* Setup coprocessor 15.
*/
/* MRC - Move to ARM Register from Coprocesor
*
* MRC{<cond>} <coproc>, <optcode_1>, <Rd>, <CRn>, <CRm> {, <optcode_2>}
*
* <coproc> - p15 ; CP15 registers
* <optcode_1> - 0
* <Rd> - R2 ; ARM destination register
* <CRn> - C1 ; Coprocesor register - first operand
* <CRm> - C0 ; Aditional coprocessor source or destination register
* <optcode_2> - 0
*
*
*
* defined in arch/arm/include/armreg.h
*
* MMU register 1 (Control Register):
* - M (bit[0]): 0 - MMU disable
* 1 - MMU enable
* - A (bit[1]): 0 - Alignment fault checking disabled
* 1 - Alignment fault checking enabled
* - S (bit[8]): System protection bit
* - R (bit[9]): ROM protection bit
*
* MMU register 2 (Translation Table Base):
*
* 3 1 1 0
* 1 4 3 0
* +-----------------------+-------------------+
* | TTB | UNP/SBZP |
* +-----------------------+-------------------+
*
* TTB - address of the currntly active first-level translation table
* UNP - UNPREDICTABLE
* and is ignored
*
* MMU register 3 (Domain Access Control):
* 16 domain (2bits field) available.
*
* MMU register 4 (Reserved):
* MMU register 5 (Fault status):
* MMU register 6 (Fault address):
* MMU register 8 (TLB functions):
* MMU register 10(TLB lockdown):
*
*/
mrc p15, 0, r2, c1, c0, 0
/* Disable MMU bit
*
* #define CPU_CONTROL_MMU_ENABLE 0x00000001
*
*/
bic r2, r2, #CPU_CONTROL_MMU_ENABLE
/* MCR - Move to Coprocesor from ARM Register */
mcr p15, 0, r2, c1, c0, 0
nop
nop
nop
/* Jump to unmapped */
mov pc, r8 /* Heave-ho! */
Lunmapped:
/*
* We want to construct a memory map that maps us
* VA==PA (SDRAM at 0x00000000). We create these
* mappings uncached and unbuffered to be safe.
*/
/*
* Step 1: Map the entire address space VA==PA.
*/
/* load table label address into R4 */
adr r4, Ltable
/* R0 == 0x4000 */
ldr r0, [r4] /* r0 = &l1table */
/* defined in arch/arm/include/arm32/pte.h */
mov r1, #(L1_TABLE_SIZE / 4) /* 4096 entry */
mov r2, #(L1_S_SIZE) /* 1MB / section */
mov r3, #(L1_S_AP(AP_KRW)) /* kernel read/write */
orr r3, r3, #(L1_TYPE_S) /* L1 entry is section */
/* 0x4000 - 0x00000402
* 0x4004 - 0x00100402
* 0x4008 - 0x00200402
* 0x400C - 0x00300402
...
*/
1:
str r3, [r0], #0x04
add r3, r3, r2
subs r1, r1, #1
bgt 1b
/*
* Step 2: Map VA 0xc0000000->0xc7fffffc to PA 0x00000000->0x07fffffc.
*/
/* R0 = 0x4000 */
ldr r0, [r4]
/* R0 = 0x7000 */
add r0, r0, #(0xc00 * 4) /* offset to 0xc00xxxxx */
mov r1, #0x80 /* 128MB */
/*
* #define L1_S_AP(x) ((x) << 10) - access permission
* AP_KRW 0x01 - kernel read/write
*
*/
mov r3, #(L1_S_AP(AP_KRW))
orr r3, r3, #(L1_TYPE_S) /* L1 descriptor - section 0x02 */
/*
* (0x7000-0x4000)/4 = 0xC00
* 0x7000 <==> 0xC000000
* 0x7000 - 0x00000402
* 0x7004 - 0x00100402
* 0x7008 - 0x00200402
* ....
*/
1:
str r3, [r0], #0x04
add r3, r3, r2
subs r1, r1, #1
bgt 1b
/*
* First-level descriptor (can be section, coarse page table, fine page table):
* Here section :)
*
* 3 1 1 0 0 0
* 1 4 3 2 1 0
* +-------------------------------------+------------------------------------------+-+-+
* | Translation base[31:14] | Modified virtual address[31:20] |0|0|
* +-------------------------------------+------------------------------------------+-+-+
*
*
* Translation table base - CP15/C2 register - must reside on 16KB boundary
*
* Eg.
* Vadd = 0xC000 2000
* Tb = 0x0000 4000
* FL-dsc[31:14] = 0b 0000 0000 0000 0000 01
* MVA[31:20] = 0b 11 0000 0000 00
* FL-dsc = 0b 0000 0000 0000 0000 0111 0000 0000 0000 (0x7000)
*
* Translating section reference (*0x7000 == 0x0000 0402):
*
* 3 2 1 1 1 1 0 0 0 0 0 0 0 0
* 1 0 9 2 1 0 9 8 5 4 3 2 1 0
* +------------------------------------+----------------+---+-+---------+-+-+-+-+-+
* | Section base address | SBZ | AP|0| Domain |1|C|B|1|0|
* +------------------------------------+----------------+---+-+---------+-+-+-+-+-+
* AP - Access Permision for this section
* Domain - one of 16 possible domains
* CB - write-back cachable, write-through cachable, noncached buffered, noncached nonbuffered
*
*
* PHYSICAL ADDRESS ( 0x0000 2000 ):
*
* 3 2 1 0
* 1 0 9 0
* +------------------------------------+-------------------------------------------+
* | Section base address | Modified virtual address[19:0] |
* +------------------------------------+-------------------------------------------+
*/
/* OK! Page table is set up. Give it to the CPU. */
adr r0, Ltable
ldr r0, [r0]
mcr p15, 0, r0, c2, c0, 0
/* Flush the old TLBs, just in case. */
mcr p15, 0, r0, c8, c7, 0
/* Set the Domain Access register. Very important! */
mov r0, #1
mcr p15, 0, r0, c3, c0, 0
/* Get ready to jump to the "real" kernel entry point... */
ldr r1, Lstart
mov r1, r1 /* Make sure the load completes! */
/* OK, let's enable the MMU. */
mrc p15, 0, r2, c1, c0, 0
orr r2, r2, #CPU_CONTROL_MMU_ENABLE
mcr p15, 0, r2, c1, c0, 0
nop
nop
nop
/* CPWAIT sequence to make sure the MMU is on... */
mrc p15, 0, r2, c2, c0, 0 /* arbitrary read of CP15 */
mov r2, r2 /* force it to complete */
mov pc, r1 /* leap to kernel entry point! */
Ltable:
.word 0x4000
/* From locore.S - arch/arm/arm32/locore.S */
Lstart:
.word start