ARMv7-A: Map all of .text, .bss, .data., stacks before enabling the MMU and caching. This is simpler and avoids fears I have about caching

This commit is contained in:
Gregory Nutt 2013-08-01 10:05:33 -06:00
parent f2195a16b2
commit b148465beb
3 changed files with 151 additions and 183 deletions

View File

@ -5248,4 +5248,8 @@
enabled by CONFIG_PAGING out of arm_head.S. That was just enabled by CONFIG_PAGING out of arm_head.S. That was just
too much conditional compilation to be supportable too much conditional compilation to be supportable
(2013-8-1). (2013-8-1).
* arch/arm/src/sama5/arm_head.S: Setup page table mappings for
all of .text, .bss, .data, stacks and heap before enabling
the MMU and caching. This is safer because it avoids the
caching issues (and much less redundant) (2013-8-1)

View File

@ -144,7 +144,6 @@
* Read/eXecute address region. This is based on NUTTX_TEXT_SIZE. * Read/eXecute address region. This is based on NUTTX_TEXT_SIZE.
*/ */
#define RX_NSECTIONS ((NUTTX_TEXT_SIZE+0x000fffff) >> 20)
#define WR_NSECTIONS ((NUTTX_RAM_SIZE+0x000fffff) >> 20) #define WR_NSECTIONS ((NUTTX_RAM_SIZE+0x000fffff) >> 20)
/**************************************************************************** /****************************************************************************
@ -207,9 +206,9 @@ __start:
/* Clear the 16K level 1 page table */ /* Clear the 16K level 1 page table */
ldr r4, .LCppgtable /* r4=phys. page table */ ldr r5, .LCppgtable /* r5=phys. page table */
#ifndef CONFIG_ARCH_ROMPGTABLE #ifndef CONFIG_ARCH_ROMPGTABLE
mov r0, r4 mov r0, r5
mov r1, #0 mov r1, #0
add r2, r0, #PGTABLE_SIZE add r2, r0, #PGTABLE_SIZE
.Lpgtableclear: .Lpgtableclear:
@ -220,6 +219,19 @@ __start:
teq r0, r2 teq r0, r2
bne .Lpgtableclear bne .Lpgtableclear
/* Load information needed to map the .text region. After the ldmia, we
* will have:
*
* R1 = Aligned, physical address of the start of the .text region
* R2 = Aligned, virtual address of the start of the .text region
* R3 = MMU flags associated with the .txt region
* R4 = The number of 1MB sections in the mapping
* R5 = The physical address of the L1 page table (from above)
*/
adr r0, .LCtextinfo /* Address of text info */
ldmia r0, {r1, r2, r3, r4} /* Load the text description */
/* Create identity mapping for first MB of the .text section to support /* Create identity mapping for first MB of the .text section to support
* this startup logic executing out of the physical address space. This * this startup logic executing out of the physical address space. This
* identity mapping will be removed by .Lvstart (see below). Of course, * identity mapping will be removed by .Lvstart (see below). Of course,
@ -228,54 +240,73 @@ __start:
*/ */
#ifndef CONFIG_IDENTITY_TEXTMAP #ifndef CONFIG_IDENTITY_TEXTMAP
ldr r0, .LCptextbase /* r0=phys. base address of .text section */ orr r0, r1, r3 /* OR MMU flags into physical address */
ldr r1, .LCtextflags /* R1=.text section MMU flags */ str r0, [r5, r1, lsr #18] /* Identity mapping */
orr r3, r1, r0 /* r3=flags + base */
str r3, [r4, r0, lsr #18] /* identity mapping */
#endif #endif
/* Create a virtual single section mapping for the first MB of the .text /* Map the entire .text regtion. We do this before enabling caches so
* address space. Now, we have the first 1MB mapping to both physical and * we know that the data will be in place in the data cache. We map the
* virtual addresses. The rest of the .text mapping will be completed in * entire text region because we don't know which parts are needed for
* .Lvstart once we have moved the physical mapping out of the way. * start-up.
* *
* Here we expect to have: * The page table base address is in R5. Each 32-bit page table entry
* r4 = Address of the base of the L1 table * maps 1 MB of address space and is indexed by the lower 20 bits of
* the virtual address in R2
*/ */
#ifdef CONFIG_IDENTITY_TEXTMAP add r2, r5, r2, lsr #18 /* R2=Offset page table address */
ldr r0, .LCptextbase /* r0=phys. base address of .text section */
ldr r1, .LCtextflags /* R1=.text section MMU flags */
orr r3, r1, r0 /* r3=flags + base */
#endif
ldr r0, .LCvtextbase /* r0=virtual base address of .text section */ /* No loop until each page table entry has been written for the .text
str r3, [r4, r0, lsr #18] /* Save the L1 entry using vaddress as an index */ * regtion.
/* NOTE: No .data/.bss access should be attempted. This temporary mapping
* can only be assumed to cover the initial .text region.
*/ */
.Lpgtextloop:
orr r0, r1, r3 /* R0: OR MMU flags into physical address */
subs r4, r4, #1 /* R4: Decrement the section count */
str r0, [r2], #4 /* Save page table entry, increment page table address */
add r1, r1, #(1024*1024) /* R1: Increment the physical address */
bne .Lpgtextloop /* Loop while R4 is non-zero */
#ifdef CONFIG_BOOT_RUNFROMFLASH #ifdef CONFIG_BOOT_RUNFROMFLASH
/* If we are executing from FLASH, then we will need an additional mapping /* If we are executing from FLASH, then we will need additional mappings for
* for the page table itself (otherwise, we will crash when we try to modify * the primay RAM region that holds the .data, .bss, stack, and heap memory.
* the page table after turning the MMU on.
* *
* Here we expect to have: * Here we expect to have:
* r4 = Address of the base of the L1 table * r5 = Address of the base of the L1 table
* *
* REVISIT: We might need this second mapping under certain conditions * REVISIT: We might need this second mapping under certain conditions
* when executing from RAM too. When the RAM region is larger than 1MB * when executing from RAM too. When the RAM region is larger than 1MB
* and the page table is in the high end of RAM, then the single mapping * and the page table is in the high end of RAM, then the single mapping
* above will not be sufficient. * above will not be sufficient.
*
* REVISIT: If the page table is not located in the primary RAM regions,
* then we will also need an additional map the page table if the page
* table resides in internal SRAM.
*
* Load information needed to map the .text region. After the ldmia, we
* will have:
*
* R1 = Aligned, physical address of the start of the .text region
* R2 = Aligned, virtual address of the start of the .text region
* R3 = MMU flags associated with the .txt region
* R4 = The number of 1MB sections in the mapping
* R5 = The physical address of the L1 page table (from above)
*/ */
ldr r0, .LCprambase /* r0=phys. base address of the primary RAM region */ adr r0, .LCraminfo /* Address of primary RAM info */
ldr r1, .LCramflags /* R1=MMU flags use with the primary RAM region */ ldmia r0, {r1, r2, r3, r4} /* Load the primary RAM description */
orr r3, r1, r0 /* r3=flags + base */ add r2, r5, r2, lsr #18 /* R2=Offset page table addres */
ldr r0, .LCvrambase /* r0=virtual base address of .text section */ /* Loop until each page table entry has been written for the primary RAM
str r3, [r4, r0, lsr #18] /* Save the L1 entry using vaddress as an index */ * region.
*/
.Lpgramloop:
orr r0, r1, r3 /* R0: OR MMU flags into physical address */
subs r4, r4, #1 /* R4: Decrement the section count */
str r0, [r2], #4 /* Save page table entry, increment page table address */
add r1, r1, #(1024*1024) /* R1: Increment the physical address */
bne .Lpgramloop /* Loop while R4 is non-zero */
#endif /* CONFIG_BOOT_RUNFROMFLASH */ #endif /* CONFIG_BOOT_RUNFROMFLASH */
#endif /* CONFIG_ARCH_ROMPGTABLE */ #endif /* CONFIG_ARCH_ROMPGTABLE */
@ -283,7 +314,7 @@ __start:
/* The following logic will set up the ARMv7-A for normal operation. /* The following logic will set up the ARMv7-A for normal operation.
* *
* Here we expect to have: * Here we expect to have:
* r4 = Address of the base of the L1 table * r5 = Address of the base of the L1 table
*/ */
/* Invalidate caches and TLBs. /* Invalidate caches and TLBs.
@ -314,11 +345,11 @@ __start:
* *
* Here we expect to have: * Here we expect to have:
* r0 = Zero * r0 = Zero
* r4 = Address of the base of the L1 table * r5 = Address of the base of the L1 table
*/ */
mcr CP15_TTBR0(r4) mcr CP15_TTBR0(r5)
mcr CP15_TTBR1(r4) mcr CP15_TTBR1(r5)
/* Set the TTB control register (TTBCR) to indicate that we are using /* Set the TTB control register (TTBCR) to indicate that we are using
* TTBR0. r0 still holds the value of zero. * TTBR0. r0 still holds the value of zero.
@ -457,64 +488,6 @@ __start:
* PC_Relative Data * PC_Relative Data
****************************************************************************/ ****************************************************************************/
/* The virtual start address of the second phase boot logic */
.type .LCvstart, %object
.LCvstart:
.long .Lvstart
.size .LCvstart, . -.LCvstart
#ifndef CONFIG_ARCH_ROMPGTABLE
/* The aligned, physical base address of the .text section */
.type .LCptextbase, %object
.LCptextbase:
.long NUTTX_TEXT_PADDR & 0xfff00000
.size .LCptextbase, . -.LCptextbase
/* The aligned, virtual base address of the .text section */
.type .LCvtextbase, %object
.LCvtextbase:
.long NUTTX_TEXT_VADDR & 0xfff00000
.size .LCvtextbase, . -.LCvtextbase
/* The MMU flags used with the .text mapping */
.type .LCtextflags, %object
.LCtextflags:
#ifdef CONFIG_BOOT_RUNFROMFLASH
.long MMU_ROMFLAGS /* MMU flags text section in FLASH/ROM */
#else
.long MMU_MEMFLAGS /* MMU flags for text section in RAM */
#endif
.size .LCtextflags, . -.LCtextflags
#ifdef CONFIG_BOOT_RUNFROMFLASH
/* The physical base address of the primary RAM region */
.type .LCprambase, %object
.LCprambase:
.long NUTTX_RAM_PADDR & 0xfff00000
.size .LCprambase, . -.LCprambase
/* The virtual base address of the primary RAM region */
.type .LCvrambase, %object
.LCvrambase:
.long NUTTX_RAM_VADDR & 0xfff00000
.size .LCvrambase, . -.LCvrambase
/* The MMU flags used with the primary RAM region */
.type .LCramflags, %object
.LCramflags:
.long MMU_MEMFLAGS /* MMU flags for RAM section */
.size .LCramflags, . -.LCramflags
#endif /* CONFIG_BOOT_RUNFROMFLASH */
#endif /* CONFIG_ARCH_ROMPGTABLE */
/* The physical base address of the page table */ /* The physical base address of the page table */
.type .LCppgtable, %object .type .LCppgtable, %object
@ -523,15 +496,63 @@ __start:
.size .LCppgtable, . -.LCppgtable .size .LCppgtable, . -.LCppgtable
#ifndef CONFIG_ARCH_ROMPGTABLE #ifndef CONFIG_ARCH_ROMPGTABLE
/* The virtual base address of the page table */ /* Text region description. The order of these fields must not change
* because the values are loaded using ldmia:
*
* 1) The aligned, physical base address of the .text section
* 2) The aligned, virtual base address of the .text section
* 3) The MMU flags to use with the .text space mapping
* 4) The number of 1MB sections in the .text region
*
* Values provided for NUTTX_TEXT_* must all be properly aligned to 1MB
* address boundaries
*/
.type .LCvpgtable, %object .type .LCtextinfo, %object
.LCvpgtable: .LCtextinfo:
.long PGTABLE_BASE_VADDR /* Virtual start of page table */ .LCptextbase:
.size .LCvpgtable, . -.LCvpgtable .long NUTTX_TEXT_PADDR /* Physical base address */
.long NUTTX_TEXT_VADDR /* Virtual base address */
.LCtextflags:
#ifdef CONFIG_BOOT_RUNFROMFLASH
.long MMU_ROMFLAGS /* MMU flags text section in FLASH/ROM */
#else
.long MMU_MEMFLAGS /* MMU flags for text section in RAM */
#endif
.long (NUTTX_TEXT_SIZE >> 20) /* Number of 1MB read-execute sections */
.size .LCtextinfo, . -.LCtextinfo
#ifdef CONFIG_BOOT_RUNFROMFLASH
/* Primary RAM region description. The order of these fields must not change
* because the values are loaded using ldmia:
*
* 1) The aligned, physical base address of the primary RAM section
* 2) The aligned, virtual base address of the primary RAM section
* 3) The MMU flags to use with the primary RAM space mapping
* 4) The number of 1MB sections in the primary RAM region
*
* Values provided for NUTTX_RAM_* must all be properly aligned to 1MB
* address boundaries
*/
.type .LCraminfo, %object
.LCraminfo:
.long NUTTX_RAM_PADDR /* Physical base address */
.long NUTTX_RAM_VADDR /* Virtual base address */
.long MMU_MEMFLAGS /* MMU flags for primary RAM section */
.long (NUTTX_RAM_SIZE >> 20) /* Number of 1MB read-execute sections */
.size .LCraminfo, . -.LCraminfo
#endif /* CONFIG_BOOT_RUNFROMFLASH */
#endif /* CONFIG_ARCH_ROMPGTABLE */ #endif /* CONFIG_ARCH_ROMPGTABLE */
/* The virtual start address of the second phase boot logic */
.type .LCvstart, %object
.LCvstart:
.long .Lvstart
.size .LCvstart, . -.LCvstart
.size __start, .-__start .size __start, .-__start
/**************************************************************************** /****************************************************************************
@ -552,82 +573,12 @@ __start:
* cover additional RAM sections. * cover additional RAM sections.
*/ */
#ifndef CONFIG_ARCH_ROMPGTABLE #if !defined(CONFIG_ARCH_ROMPGTABLE) && !defined(CONFIG_IDENTITY_TEXTMAP)
#ifndef CONFIG_IDENTITY_TEXTMAP ldr r5, .LCvpgtable /* r5=Virtual page table base address */
ldr r4, .LCvpgtable /* r4=virtual page table base address */ ldr r3, .LCptextbase /* r0=Physical base address of .text section */
ldr r3, .LCvtextbase /* r0=virtual base address of .text section */
mov r0, #0 /* flags + base = 0 */ mov r0, #0 /* flags + base = 0 */
str r3, [r4, r3, lsr #18] /* identity mapping */ str r3, [r5, r3, lsr #18] /* identity mapping */
#endif #endif /* !CONFIG_ARCH_ROMPGTABLE && !CONFIG_IDENTITY_TEXTMAP */
/* Get the following value (if we did not already do so above):
*
* R4 = Virtual address of the page table
* R3 = Physical address of the NuttX execution space (aligned to a
* one megabyte addres boundary
*/
#ifdef CONFIG_IDENTITY_TEXTMAP
ldr r4, .LCvpgtable /* r4=virtual page table */
#endif
ldr r3, .LCptextbase /* r3=Aligned Nuttx start address (physical) */
/* Now setup the page tables for our normal mapped execution region.
* We round NUTTX_TEXT_VADDR down to the nearest megabyte boundary.
*/
ldr r1, .LCtextflags /* R1=.text section MMU flags */
add r3, r3, r1 /* r3=flags + base */
add r0, r4, #(NUTTX_TEXT_VADDR & 0xfff00000) >> 18
str r3, [r0], #4
/* Now map the remaining RX_NSECTIONS-1 sections of the executable
* memory region.
*/
.rept RX_NSECTIONS-1
add r3, r3, #SECTION_SIZE
str r3, [r0], #4
.endr
/* If we are executing from RAM with a fixed page configuration, then
* we can assume that the above contiguous mapping included all of the
* .text, .data, .bss, heap, etc. But if we are executing from FLASH,
* then the RAM area is probably in a separate physical address region
* and will require a separate mapping. Or, if we are supporting on-demand
* paging of the .text region, then the RAM-based .data/.bss/heap section
* will still probably be located in a separate (virtual) address region.
*
* Here we still have R4 = The virtual address of the page table.
*/
#ifdef CONFIG_BOOT_RUNFROMFLASH
/* Get R3 = Value of RAM L1 page table entry */
ldr r3, .LCprambase /* r3=Aligned Nuttx RAM address (physical) */
ldr r1, .LCramflags /* R1=.bss/.data section MMU flags */
add r3, r3, r1 /* r3=flags + base */
/* Now setup the page tables for our normal mapped RAM region.
* We round NUTTX_RAM_VADDR down to the nearest megabyte boundary.
*/
add r0, r4, #(NUTTX_RAM_VADDR & 0xfff00000) >> 18
str r3, [r0], #4
/* Now map the remaining WR_NSECTIONS-1 sections of the RAM memory
* region.
*/
.rept WR_NSECTIONS-1
add r3, r3, #SECTION_SIZE
str r3, [r0], #4
.endr
#endif /* CONFIG_BOOT_RUNFROMFLASH */
#endif /* CONFIG_ARCH_ROMPGTABLE */
/* Zero BSS and set up the stack pointer */ /* Zero BSS and set up the stack pointer */
@ -681,6 +632,16 @@ __start:
* end of memory. See g_idle_topstack below. * end of memory. See g_idle_topstack below.
*/ */
#ifndef CONFIG_ARCH_ROMPGTABLE
/* The virtual base address of the page table */
.type .LCvpgtable, %object
.LCvpgtable:
.long PGTABLE_BASE_VADDR /* Virtual start of page table */
.size .LCvpgtable, . -.LCvpgtable
#endif /* CONFIG_ARCH_ROMPGTABLE */
.type .Linitparms, %object .type .Linitparms, %object
.Linitparms: .Linitparms:
.long _sbss .long _sbss

View File

@ -443,7 +443,8 @@
# define NUTTX_TEXT_VADDR (CONFIG_FLASH_VSTART & 0xfff00000) # define NUTTX_TEXT_VADDR (CONFIG_FLASH_VSTART & 0xfff00000)
# define NUTTX_TEXT_PADDR (CONFIG_FLASH_START & 0xfff00000) # define NUTTX_TEXT_PADDR (CONFIG_FLASH_START & 0xfff00000)
# define NUTTX_TEXT_SIZE (CONFIG_FLASH_END - NUTTX_TEXT_VADDR) # define NUTTX_TEXT_PEND ((CONFIG_FLASH_END + 0x000fffff) & 0xfff00000)
# define NUTTX_TEXT_SIZE (NUTTX_TEXT_PEND - NUTTX_TEXT_PADDR)
/* In the default configuration, the primary RAM use for .bss and .data /* In the default configuration, the primary RAM use for .bss and .data
* is the internal SRAM. * is the internal SRAM.
@ -451,7 +452,8 @@
# define NUTTX_RAM_VADDR (CONFIG_RAM_VSTART & 0xfff00000) # define NUTTX_RAM_VADDR (CONFIG_RAM_VSTART & 0xfff00000)
# define NUTTX_RAM_PADDR (CONFIG_RAM_START & 0xfff00000) # define NUTTX_RAM_PADDR (CONFIG_RAM_START & 0xfff00000)
# define NUTTX_RAM_SIZE (CONFIG_RAM_END - NUTTX_RAM_PADDR) # define NUTTX_RAM_PEND ((CONFIG_RAM_END + 0x000fffff) & 0xfff00000)
# define NUTTX_RAM_SIZE (NUTTX_RAM_PEND - NUTTX_RAM_PADDR)
#else #else
/* Otherwise we are running from some kind of RAM (ISRAM or SDRAM). /* Otherwise we are running from some kind of RAM (ISRAM or SDRAM).
@ -460,7 +462,8 @@
# define NUTTX_TEXT_VADDR (CONFIG_RAM_VSTART & 0xfff00000) # define NUTTX_TEXT_VADDR (CONFIG_RAM_VSTART & 0xfff00000)
# define NUTTX_TEXT_PADDR (CONFIG_RAM_START & 0xfff00000) # define NUTTX_TEXT_PADDR (CONFIG_RAM_START & 0xfff00000)
# define NUTTX_TEXT_SIZE (CONFIG_RAM_END - NUTTX_TEXT_VADDR) # define NUTTX_TEXT_PEND ((CONFIG_RAM_END + 0x000fffff) & 0xfff00000)
# define NUTTX_TEXT_SIZE (NUTTX_TEXT_PEND - NUTTX_TEXT_PADDR)
#endif #endif
/* MMU Page Table Location /* MMU Page Table Location