Difference between revisions of "Memory layout"

From Nintendo Switch Brew
Jump to navigation Jump to search
m
 
(44 intermediate revisions by 7 users not shown)
Line 3: Line 3:
  
 
There are two regions randomized and enforced by the kernel, each one with upper bits random and 2MB-aligned:
 
There are two regions randomized and enforced by the kernel, each one with upper bits random and 2MB-aligned:
* Heap region, available from [[SVC#svcGetInfo]].
+
* ReservedHeapRegion, available from [[SVC#svcGetInfo]].
* Stack mapping region, available from [[SVC#svcGetInfo]].
+
* ReservedMapRegion, available from [[SVC#svcGetInfo]].
 +
* [2.0.0+] NewReservedMapRegion, available from [[SVC#svcGetInfo]].
 +
* [2.0.0+] TlsIoRegion, not available to userspace.
  
 
The main binary is placed at an address that is provided to the kernel by Loader via [[SVC#svcCreateProcess]].
 
The main binary is placed at an address that is provided to the kernel by Loader via [[SVC#svcCreateProcess]].
Line 17: Line 19:
  
 
On version [[1.0.0]], the initial binaries loaded into memory by the kernel always have the upper 32-bits as all-zero, so there are 6 fewer bits of layout randomization.  
 
On version [[1.0.0]], the initial binaries loaded into memory by the kernel always have the upper 32-bits as all-zero, so there are 6 fewer bits of layout randomization.  
 +
 +
Binaries loaded within the main-binary-region are loaded into memory in the following order, immediately after each other, for the binaries which exist in [[ExeFS]]:
 +
* rtld
 +
* main
 +
* subsdk*
 +
* sdk
  
 
== ASLR Implementation ==
 
== ASLR Implementation ==
 +
The kernel uses a MT19937 random number generator, seeded by [[SMC#GenerateRandomBytes|smcGenerateRandomBytes]].
  
 
=== 1.0.0 ===
 
=== 1.0.0 ===
Line 58: Line 67:
 
For userland pages, the kernel has same access as userland (either both are read-only or both are read-write). It does not have SMAP. The previous rule has one exception: pages that are mapped unreadable in usermode are still forced readable from kernelmode.
 
For userland pages, the kernel has same access as userland (either both are read-only or both are read-write). It does not have SMAP. The previous rule has one exception: pages that are mapped unreadable in usermode are still forced readable from kernelmode.
  
As of [[2.0.0]] KASLR is not used.
+
KASLR is being used since [[5.0.0]], but not before, with the following pseudocode (might contains some errors):
 +
 
 +
<pre>
 +
DRAM crt0 mapping (ttbr1): offsets DRAM with (rand64ViaSmc() % 0x3FFF0 << 21), allocates exactly (end - _start) + 1GB.
 +
This is a "linear" mapping. Permissions are set properly.
 +
 
 +
KERN_ADDRSPACE      := [VA(_start) : min(0xFFFFFFFFFFE00000 - VA(_start), 0x40000000)]
 +
DRAM_FROM_SECTION1  := DRAM[0x808cd000:] // 0x808cd000 corresponds to start of section1 (loaded INI1) data, reused later
 +
 
 +
/* Global Randomize range: 0xFFFFFF8000000000 to 0xFFFFFFFFFFE00000. */
 +
/*
 +
    Randomize picks a random integer in ranges, clears as many low bits required,
 +
    then checks if the address is acceptable, if not it attempts to iterate through page table entries.
 +
   
 +
    If it doesn't find anything, it picks another integer. In case of general failure, the whole operation
 +
    may be done from the start again (maybe ?).
 +
*/
 +
 
 +
/* Core0 executes this big KASLR function, then powers on the other CPUs (?). */
 +
MapPartially(RandomizeL1Boundary(DRAM, sizeof(DRAM)) -> DRAM_FROM_SECTION1: offsetof DRAM_FROM_SECTION1,
 +
 
 +
/* Randomize */
 +
KERN_ADDRSPACE {
 +
    Randomize(IOAndInitialStacks, 0x2000000) {
 +
        Map(Randomize(UartA, 0x1000)) -> UartA,
 +
        GuardPage,
 +
        Map(Randomize(Gicd, 0x1000)) -> Gicd,
 +
        GuardPage,
 +
        Map(Randomize(Gicc, 0x1000)) -> Gicc,
 +
        ForEachCore {
 +
            GuardPage,
 +
            Map(Randomize(EntryThreadStack, 0x1000)) -> NextFreePage(),
 +
            GuardPage,
 +
            Map(Randomize(IdleSchedulerThreadStack, 0x1000)) -> NextFreePage(),
 +
            GuardPage,
 +
            Map(Randomize(EL1AbortStack, 0x1000)) -> NextFreePage(),
 +
        }
 +
    },
 +
   
 +
    Randomize(KernelStacks, 0xE00000),
 +
    Map(Randomize(SlabHeaps, 0x7E9000, AFTER(VA(_end)) -> PA(_end)),
 +
    Randomize(Kip1DecompressionBuffer, 0x8000000), /* 128 MB VA range */
 +
},
 +
 
 +
Map(RandomizePageBoundary(GuardPage + KCoreContext * 4)) -> NextFreePages(4)
 +
</pre>
  
 
== 1.0.0 ==
 
== 1.0.0 ==
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Cores || Virtual || Physical || Size || Attributes || Permissions || Description
+
! Virtual || Physical || Size || Attributes || Permissions || Description
 +
|-
 +
| 0xFFFFFFFFBFC00000-0xFFFFFFFFBFC45FFF || 0x800A0000 || 0x46000 || 0x78B || R-X || Kernel .text
 +
|-
 +
| 0xFFFFFFFFBFC46000-0xFFFFFFFFBFC48FFF || 0x800E6000 || 0x3000 || 0x6000000000078B || R-- || Kernel .rodata
 +
|-
 +
| 0xFFFFFFFFBFC49000-0xFFFFFFFFBFC4FFFF || 0x800E9000 || 0x7000 || 0x6000000000070B || RW- || Kernel .data+.bss
 +
|-
 +
| 0xFFFFFFFFBFD72000-0xFFFFFFFFBFD72FFF || 0x6000F000 || 0x1000 || 0x60000000000607 || RW- || Exception vectors
 +
|-
 +
| 0xFFFFFFFFBFDB5000-0xFFFFFFFFBFDB5FFF || 0x60007000 || 0x1000 || 0x60000000000607 || RW- || Flow controller
 +
|-
 +
| 0xFFFFFFFFBFDB7000-0xFFFFFFFFBFDB7FFF || 0x60004000 || 0x1000 || 0x60000000000607 || RW- || Primary ICTLR
 +
|-
 +
| 0xFFFFFFFFBFDB9000-0xFFFFFFFFBFDB9FFF || 0x60001000 || 0x1000 || 0x60000000000607 || RW- || Resource Semaphore
 +
|-
 +
| 0xFFFFFFFFBFDBB000-0xFFFFFFFFBFDBBFFF || 0x70016000 || 0x2000 || 0x60000000000607 || RW- || ATOMICS
 +
|-
 +
| 0xFFFFFFFFBFDBE000-0xFFFFFFFFBFDBEFFF || 0x7000E000 || 0x1000 || 0x60000000000607 || RW- || PMC
 +
|-
 +
| 0xFFFFFFFFBFDC0000-0xFFFFFFFFBFDC0FFF || 0x60006000 || 0x1000 || 0x60000000000607 || RW- || Clock and reset
 +
|-
 +
| 0xFFFFFFFFBFDC2000-0xFFFFFFFFBFDC2FFF || 0x7001D000 || 0x1000 || 0x60000000000607 || RW- || MC1
 +
|-
 +
| 0xFFFFFFFFBFDC4000-0xFFFFFFFFBFDC4FFF || 0x7001C000 || 0x1000 || 0x60000000000607 || RW- || MC0
 
|-
 
|-
| All || 0xFFFFFFFFBFC00000-0xFFFFFFFFBFC45FFF || 0x800A0000 || 0x46000 || 0x78B || R-X || Kernel .text
+
| 0xFFFFFFFFBFDC6000-0xFFFFFFFFBFDC6FFF || 0x70019000 || 0x1000 || 0x60000000000607 || RW- || MC
 
|-
 
|-
| All || 0xFFFFFFFFBFC46000-0xFFFFFFFFBFC48FFF || 0x800E6000 || 0x3000 || 0x6000000000078B || R-- || Kernel .rodata
+
| 0xFFFFFFFFBFDC8000-0xFFFFFFFFBFDC8FFF || 0x70006000 || 0x1000 || 0x60000000000607 || RW- || UART-A
 
|-
 
|-
| All || 0xFFFFFFFFBFC49000-0xFFFFFFFFBFC4FFFF || 0x800E9000 || 0x7000 || 0x6000000000070B || RW- || Kernel .data+.bss
+
| 0xFFFFFFFFBFDCA000-0xFFFFFFFFBFDCBFFF || 0x80060000 || 0x2000 || 0x6000000000070B || RW- ||
 
|-
 
|-
| All || 0xFFFFFFFFBFDC0000-0xFFFFFFFFBFDC0FFF || 0x60006000 || 0x1000 || 0x60000000000607 || RW- ||
+
| 0xFFFFFFFFBFDCE000-0xFFFFFFFFBFDCFFFF || 0x80068000 || 0x2000 || 0x6000000000070B || RW- || Kernel main stack (cpu0)
 
|-
 
|-
| All || 0xFFFFFFFFBFDC2000-0xFFFFFFFFBFDC2FFF || 0x7001D000 || 0x1000 || 0x60000000000607 || RW- ||
+
| 0xFFFFFFFFBFDD2000-0xFFFFFFFFBFDD2FFF || 0x80070000 || 0x1000 || 0x6000000000070B || RW- || Kernel runner stack (cpu0)
 
|-
 
|-
| All || 0xFFFFFFFFBFDC4000-0xFFFFFFFFBFDC4FFF || 0x7001C000 || 0x1000 || 0x60000000000607 || RW- ||
+
| 0xFFFFFFFFBFDD4000-0xFFFFFFFFBFDD5FFF || 0x80062000 || 0x2000 || 0x6000000000070B || RW- ||
 
|-
 
|-
| All || 0xFFFFFFFFBFDC6000-0xFFFFFFFFBFDC6FFF || 0x70019000 || 0x1000 || 0x60000000000607 || RW- ||
+
| 0xFFFFFFFFBFDD8000-0xFFFFFFFFBFDD9FFF || 0x8006A000 || 0x2000 || 0x6000000000070B || RW- || Kernel main stack (cpu1)
 
|-
 
|-
| All || 0xFFFFFFFFBFDC8000-0xFFFFFFFFBFDC8FFF || 0x70006000 || 0x1000 || 0x60000000000607 || RW- ||
+
| 0xFFFFFFFFBFDDC000-0xFFFFFFFFBFDDCFFF || 0x80071000 || 0x1000 || 0x6000000000070B || RW- || Kernel runner stack (cpu1)
 
|-
 
|-
| All || 0xFFFFFFFFBFDCA000-0xFFFFFFFFBFDCBFFF || 0x80060000 || 0x2000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDDE000-0xFFFFFFFFBFDDFFFF || 0x80064000 || 0x2000 || 0x6000000000070B || RW- ||
 
|-
 
|-
| All || 0xFFFFFFFFBFDCE000-0xFFFFFFFFBFDCFFFF || 0x80068000 || 0x2000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDE2000-0xFFFFFFFFBFDE3FFF || 0x8006C000 || 0x2000 || 0x6000000000070B || RW- || Kernel main stack (cpu2)
 
|-
 
|-
| All || 0xFFFFFFFFBFDD2000-0xFFFFFFFFBFDD2FFF || 0x80070000 || 0x1000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDE6000-0xFFFFFFFFBFDE6FFF || 0x80072000 || 0x1000 || 0x6000000000070B || RW- || Kernel runner stack (cpu2)
 
|-
 
|-
| All || 0xFFFFFFFFBFDD4000-0xFFFFFFFFBFDD5FFF || 0x80062000 || 0x2000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDE8000-0xFFFFFFFFBFDE9FFF || 0x80066000 || 0x2000 || 0x6000000000070B || RW- ||
 
|-
 
|-
| All || 0xFFFFFFFFBFDD8000-0xFFFFFFFFBFDD9FFF || 0x8006A000 || 0x2000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDEC000-0xFFFFFFFFBFDEDFFF || 0x8006E000 || 0x2000 || 0x6000000000070B || RW- || Kernel main stack (cpu3)
 
|-
 
|-
| All || 0xFFFFFFFFBFDDC000-0xFFFFFFFFBFDDCFFF || 0x80071000 || 0x1000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDF0000-0xFFFFFFFFBFDF0FFF || 0x80073000 || 0x1000 || 0x6000000000070B || RW- || Kernel runner stack (cpu3)
 
|-
 
|-
| All || 0xFFFFFFFFBFDDE000-0xFFFFFFFFBFDDFFFF || 0x80064000 || 0x2000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDFB000-0xFFFFFFFFBFDFBFFF || 0x50041000 || 0x1000 || 0x60000000000607 || RW- || ARM Interrupt Distributor
 
|-
 
|-
| All || 0xFFFFFFFFBFDE2000-0xFFFFFFFFBFDE3FFF || 0x8006C000 || 0x2000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDFD000-0xFFFFFFFFBFDFDFFF || 0x50042000 || 0x1000 || 0x60000000000607 || RW- || Interrupt Controller Physical CPU interface
 
|-
 
|-
| All || 0xFFFFFFFFBFDE6000-0xFFFFFFFFBFDE6FFF || 0x80072000 || 0x1000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDF2000-0xFFFFFFFFBFDF3FFF || 0x80060000+(cpuid*0x2000) || 0x2000 || 0x6000000000070B || RW- ||
 
|-
 
|-
| All || 0xFFFFFFFFBFDE8000-0xFFFFFFFFBFDE9FFF || 0x80066000 || 0x2000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDF6000-0xFFFFFFFFBFDF7FFF || 0x80068000+(cpuid*0x2000) || 0x2000 || 0x6000000000070B || RW- || Kernel main stack (per-core self-mirror)
 
|-
 
|-
| All || 0xFFFFFFFFBFDF0000-0xFFFFFFFFBFDF0FFF || 0x80073000 || 0x1000 || 0x6000000000070B || RW- ||
+
| 0xFFFFFFFFBFDFF000-0xFFFFFFFFBFDFFFFF || 0x80084000+(cpuid*0x1000) || 0x1000 || 0x6000000000070B || RW- || Kernel runner stack (per-core self-mirror)
 
|-
 
|-
| All || 0xFFFFFFFE00000000-... || 0x80000000 || ... || 0x60000000000709 || RW- || Raw DRAM access
+
| 0xFFFFFFFE00000000-... || 0x80000000 || ... || 0x60000000000709 || RW- || Raw DRAM access
 
|}
 
|}
  
Line 156: Line 234:
 
|-
 
|-
 
| All || 0xFFFFFFF800000000-... || 0x80000000 || ... || 0x60000000000709 || RW- || Raw DRAM access
 
| All || 0xFFFFFFF800000000-... || 0x80000000 || ... || 0x60000000000709 || RW- || Raw DRAM access
 +
|}
 +
 +
== 3.0.0 ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Cores || Virtual || Physical || Size || Attributes || Permissions || Description
 +
|-
 +
| All || 0xFFFFFFF7FFC00000-0xFFFFFFF7FFC4AFFF || 0x800A0000 || 0x4B000 || 0x78B || R-X || Kernel .text
 +
|-
 +
| All || 0xFFFFFFF7FFC4B000-0xFFFFFFF7FFC4DFFF || 0x800EB000 || 0x3000 || 0x6000000000078B || R-- || Kernel .rodata
 +
|-
 +
| All || 0xFFFFFFF7FFC4E000-0xFFFFFFF7FFC5AFFF || 0x800EE000 || 0xD000 || 0x6000000000070B || RW- || Kernel .data+.bss
 +
|-
 +
| All || 0xFFFFFFF7FFDAC000-0xFFFFFFF7FFDACFFF || 0x60006000 || 0x1000 || 0x60000000000607 || RW- || Clock and Reset
 +
|-
 +
| All || 0xFFFFFFF7FFDAE000-0xFFFFFFF7FFDAEFFF || 0x7001D000 || 0x1000 || 0x60000000000607 || RW- || MC1
 +
|-
 +
| All || 0xFFFFFFF7FFDB0000-0xFFFFFFF7FFDB0FFF || 0x7001C000 || 0x1000 || 0x60000000000607 || RW- || MC0
 +
|-
 +
| All || 0xFFFFFFF7FFDB2000-0xFFFFFFF7FFDB2FFF || 0x70019000 || 0x1000 || 0x60000000000607 || RW- || MC
 +
|-
 +
| All || 0xFFFFFFF7FFDB4000-0xFFFFFFF7FFDB4FFF || 0x70006000 || 0x1000 || 0x60000000000607 || RW- || UART-A
 +
|-
 +
| All || 0xFFFFFFF7FFDFB000-0xFFFFFFF7FFDFBFFF || 0x50041000 || 0x1000 || 0x60000000000607 || RW- || ARM Interrupt Distributor
 +
|-
 +
| All || 0xFFFFFFF7FFDFD000-0xFFFFFFF7FFDFDFFF || 0x50042000 || 0x1000 || 0x60000000000607 || RW- || Interrupt Controller Physical CPU interface
 +
|}
 +
 +
== 4.0.0 ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Cores || Virtual || Physical || Size || Attributes || Permissions || Description
 +
|-
 +
| All || 0xFFFFFFF7FFC00000-0xFFFFFFF7FFC50FFF || 0x800A0000 || 0x51000 || 0x4000000000078B || R-X || Kernel .text
 +
|-
 +
| All || 0xFFFFFFF7FFC51000-0xFFFFFFF7FFC53FFF || 0x800F1000 || 0x3000 || 0x6000000000078B || R-- || Kernel .rodata
 +
|-
 +
| All || 0xFFFFFFF7FFC54000-0xFFFFFFF7FFC61FFF || 0x800F4000 || 0xE000 || 0x6000000000070B || RW- || Kernel .data+.bss
 +
|-
 +
| All || 0xFFFFFFF7FFDAC000-0xFFFFFFF7FFDACFFF || 0x60006000 || 0x1000 || 0x60000000000607 || RW- || Clock and Reset
 +
|-
 +
| All || 0xFFFFFFF7FFDAE000-0xFFFFFFF7FFDAEFFF || 0x7001D000 || 0x1000 || 0x60000000000607 || RW- || MC1
 +
|-
 +
| All || 0xFFFFFFF7FFDB0000-0xFFFFFFF7FFDB0FFF || 0x7001C000 || 0x1000 || 0x60000000000607 || RW- || MC0
 +
|-
 +
| All || 0xFFFFFFF7FFDB2000-0xFFFFFFF7FFDB2FFF || 0x70019000 || 0x1000 || 0x60000000000607 || RW- || MC
 +
|-
 +
| All || 0xFFFFFFF7FFDB4000-0xFFFFFFF7FFDB4FFF || 0x70006000 || 0x1000 || 0x60000000000607 || RW- || UART-A
 +
|-
 +
| All || 0xFFFFFFF7FFDFB000-0xFFFFFFF7FFDFBFFF || 0x50041000 || 0x1000 || 0x60000000000607 || RW- || ARM Interrupt Distributor
 +
|-
 +
| All || 0xFFFFFFF7FFDFD000-0xFFFFFFF7FFDFDFFF || 0x50042000 || 0x1000 || 0x60000000000607 || RW- || Interrupt Controller Physical CPU interface
 
|}
 
|}
  
Line 183: Line 313:
 
| 0x800XX000
 
| 0x800XX000
 
|}
 
|}
 +
 +
== Notes ==
 +
=== 2.0.0 ===
 +
  Granule size for TTBR0*_EL1 is 4KB.
 +
  TTBR0_EL1 vmem starts at vaddr 0x0.
 +
  vmem end-addr for TTBR1_EL1 is 0xffffffffffffffff. vmem start-addr for TTBR1_EL1 is 0xFFFFFFF000000000.
 +
  T0SZ = 31. Hence, bit-size of the TTBR0*_EL1 vmem region is 33. (0x0000000200000000)
 +
  T1SZ = 28. Hence, bit-size of the TTBR1*_EL1 vmem region is 36. (0x0000001000000000)
 +
 
 +
  Note: ARM config for TTBR0 is presumably configured for userland later.
 +
 
 +
  See arm-doc for "Table D4-25 Translation table entry addresses when using the 4KB translation granule".
 +
 
 +
  See arm-doc for "Overview of VMSAv8-64 address translation using the 4KB translation granule".
 +
 
 +
  See arm-doc for "Table D4-11 TCR.TnSZ values and IA ranges, 4K granule with no concatenation of tables".
 +
  Both TTBR*_EL1 use "Initial lookup level" 1. Therefore, the TTBR*_EL1 tables are level1.
 +
 
 +
  Due to T*SZ, Stage1/Stage2 translation for the initial table(level1) are the same, except Stage2 uses hard-coded T0SZ.
 +
  Basically, the table is accessed as: ((u64*)tablebase)[<IA[y:30]>], where y = (37-T*SZ)+26. That is, starting at bit "y" ending(inclusive) at bit30. For TTBR0*_EL1, y = 32, while for TTBR1_EL1 y = 35.
 +
  Hence, for TTBR0, index=((vaddr>>30) & 0x7), and for TTBR1, index=((vaddr>>30) & 0x3f).
 +
 +
"Vector Base Address Register (EL1)" = 0xfffffff7ffc50800.
 +
 +
The table for TTBR0 only contains the following:
 +
* Vmem 0x80000000 is mapped to physmem 0x80000000, using a size loaded from a register. This is only done when: "endaddr = 0x7fffffff + size; if(endaddr >= 0x80000001){...}"
 +
** The size is loaded from: "(u32 *0x70019050 & 0x3fff) << 20;"
 +
** The value written to the MMU-table descriptor is: "physaddr | val | 0x709;". val is 1<<52 when "tmp>>34" is non-zero and when "if((physaddr & 0x3c0000000) == 0)", otherwise val=0. tmp=size at the start and increased by 0xffffffffc0000000 each loop iteration. physaddr is increased by 0x40000000 each loop iteration.
 +
 +
TTBR1:
 +
* vmem 0xFFFFFFF800000000 is mapped to physmem 0x80000000. Similar to above, except tmp=0 due to wrap-around, etc. This also has usermode/kernel XN enabled in the descriptor ORR-value. The chunksize used when increasing addr is 0xfffffff840000000, with another +=0x40000000 separate from the addr cmp for the loop.
 +
** "endaddr = 0x3fffffff + (<size from above> | 0xfffffff800000000); enaddr = (endaddr & 0xffffffffc0000000)-1; if(endaddr >= 0xfffffff800000001){<map mem>}"
 +
 +
* Initializes level2 pagetable descriptor for vmem 0xFFFFFFF7C0000000. descriptor = 0x3 | physaddr. physaddr is core-specific.
 +
* Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FFC00000. descriptor = 0x3 | physaddr. physaddr is core-specific.
 +
* The content of the pagetable for the following level3 mmutables are not initialized in the main mmutable-init func. descriptor = 0x8007c003(0x3 | <physaddr tablebase>). tablebase=0x8007c000.
 +
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FEE00000. physaddr = tablebase + (0x1<<12).
 +
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF000000. physaddr = tablebase + (0x2<<12).
 +
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF200000. physaddr = tablebase + (0x3<<12).
 +
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FFA00000. physaddr = tablebase + (0x7<<12).
 +
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FEC00000. physaddr = tablebase.
 +
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF400000. physaddr = tablebase + (0x4<<12).
 +
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF600000. physaddr = tablebase + (0x5<<12).
 +
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF800000. physaddr = tablebase + (0x6<<12).
  
 
= Secure Monitor =
 
= Secure Monitor =
 +
Unless otherwise mentionned, block descriptors (in our case, the one uses for the DRAM identity mapping) are all ORRed by 0x401 and page descriptors by 0x403.
 +
 
 +
== [[1.0.0]] ==
 +
{| class="wikitable" border="1"
 +
|-
 +
! Vmem
 +
! Physmem
 +
! Size
 +
! Descriptor ORR-value
 +
! Permissions
 +
! Description
 +
|-
 +
| 0x1F0000000
 +
| 0x50041000
 +
| 0x1000
 +
| 0x40000000000324
 +
|
 +
| ARM Interrupt Distributor
 +
|-
 +
| 0x1F0002000
 +
| 0x50042000
 +
| 0x1000
 +
| 0x40000000000324
 +
|
 +
| Interrupt Controller Physical CPU Interface
 +
|-
 +
| 0x1F0005000
 +
| 0x70006000
 +
| 0x1000
 +
| 0x40000000000324
 +
|
 +
| UART-A
 +
|-
 +
| 0x1F0007000
 +
| 0x60006000
 +
| 0x1000
 +
| 0x40000000000324
 +
|
 +
| Clock and Reset
 +
|-
 +
| 0x1F0009000
 +
| 0x7000E000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| PMC
 +
|-
 +
| 0x1F000B000
 +
| 0x60005000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| TMR
 +
|-
 +
| 0x1F000D000
 +
| 0x6000C000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| System Registers
 +
|-
 +
| 0x1F000F000
 +
| 0x70012000
 +
| 0x2000
 +
| 0x40000000000304
 +
|
 +
| SE
 +
|-
 +
| 0x1F0012000
 +
| 0x700F0000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| SYSCTR0
 +
|-
 +
| 0x1F0014000
 +
| 0x70019000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| MC
 +
|-
 +
| 0x1F0016000
 +
| 0x7000F000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| FUSE
 +
|-
 +
| 0x1F0018000
 +
| 0x70000000
 +
| 0x4000
 +
| 0x40000000000304
 +
|
 +
| MISC
 +
|-
 +
| 0x1F001D000
 +
| 0x60007000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| Flow controller
 +
|-
 +
| 0x1F001F000
 +
| 0x40002000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| IRAM
 +
|-
 +
| 0x1F0021000
 +
| 0x7000D000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| I2C-5
 +
|-
 +
| 0x1F0023000
 +
| 0x6000D000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| GPIO-1
 +
|-
 +
| 0x1F0025000
 +
| 0x7000C000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| I2C
 +
|-
 +
| 0x1F0180000
 +
| 0x40020000
 +
| 0x10000
 +
| 0x40000000000324
 +
|
 +
| IRAM
 +
|-
 +
| 0x1F01A0000
 +
| 0x7C010000
 +
| 0x10000
 +
| 0x40000000000384
 +
|
 +
| TZRAM
 +
|-
 +
| 0x1F01C3000
 +
| 0x80010000
 +
| 0x10000
 +
| 0x40000000000324
 +
|
 +
| EMEM
 +
|-
 +
| 0x1F01C2000
 +
| 0x8000F000
 +
| 0x1000
 +
| 0x40000000000324
 +
|
 +
| EMEM
 +
|-
 +
| 0x1F01E0000
 +
| 0x7C013000
 +
| 0xB000
 +
| 0x304
 +
|
 +
| TZRAM (Secure Monitor)
 +
|-
 +
| 0x1F01F0000
 +
| 0x7C01E000
 +
| 0x2000
 +
| 0x304
 +
|
 +
| TZRAM (Secure Monitor and ARMv8 init)
 +
|-
 +
| 0x1F01F6000
 +
| 0x7C01E000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| TZRAM
 +
|-
 +
| 0x1F01F8000
 +
| 0x7C01F000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| TZRAM
 +
|-
 +
| 0x1F01FA000
 +
| 0x7C010000
 +
| 0x1000
 +
| 0x304
 +
|
 +
| TZRAM (Secure Monitor exception vectors)
 +
|-
 +
| 0x1F01FC000
 +
| 0x7C011000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| TZRAM
 +
|-
 +
| 0x1F01FE000
 +
| 0x7C012000
 +
| 0x1000
 +
| 0x40000000000304
 +
|
 +
| TZRAM
 +
|}
  
 
== [[2.0.0]] ==
 
== [[2.0.0]] ==
Line 244: Line 626:
 
| 0x40000000000304
 
| 0x40000000000304
 
|  
 
|  
| RTC
+
| PMC
 
|-
 
|-
 
| 0x1F008B000
 
| 0x1F008B000
Line 384: Line 766:
 
| 0x300
 
| 0x300
 
|  
 
|  
| TZRAM (Secure Monitor init)
+
| TZRAM (Secure Monitor and ARMv8 init)
 +
|-
 +
| 0x1F01F4000
 +
| <varies>
 +
| 0x1000
 +
| 0x40000000000320
 +
|
 +
| DRAM (SPL .bss buffer visible to the Security Engine)
 
|-
 
|-
 
| 0x1F01F6000
 
| 0x1F01F6000
Line 422: Line 811:
 
|}
 
|}
  
= Notes =
+
== [[5.0.0]] ==
== 2.0.0 ==
+
5.0.0 modified the address map to have separate .text, .rodata, and .rwdata segments, instead of a single RWX segment.
  Granule size for TTBR0*_EL1 is 4KB.
+
 
  TTBR0_EL1 vmem starts at vaddr 0x0.
+
However, the .rodata and .rwdata segments are both (mistakenly?) mapped R-W.
  vmem end-addr for TTBR1_EL1 is 0xffffffffffffffff. vmem start-addr for TTBR1_EL1 is 0xFFFFFFF000000000.
+
 
  T0SZ = 31. Hence, bit-size of the TTBR0*_EL1 vmem region is 33. (0x0000000200000000)
+
Because the same L3 page is shared for all mappings, this required modifying segment layout significantly to prevent clashes.
  T1SZ = 28. Hence, bit-size of the TTBR1*_EL1 vmem region is 36. (0x0000001000000000)
+
 
 
+
{| class="wikitable" border="1"
  Note: ARM config for TTBR0 is presumably configured for userland later.
+
|-
 
+
! Vmem
  See arm-doc for "Table D4-25 Translation table entry addresses when using the 4KB translation granule".
+
! Physmem
 
+
! Size
  See arm-doc for "Overview of VMSAv8-64 address translation using the 4KB translation granule".
+
! Descriptor ORR-value
 
+
! Description
  See arm-doc for "Table D4-11 TCR.TnSZ values and IA ranges, 4K granule with no concatenation of tables".
+
|-
  Both TTBR*_EL1 use "Initial lookup level" 1. Therefore, the TTBR*_EL1 tables are level1.
+
| 0x7C010000
 
+
| 0x7C010000
  Due to T*SZ, Stage1/Stage2 translation for the initial table(level1) are the same, except Stage2 uses hard-coded T0SZ.
+
| 0x10000
  Basically, the table is accessed as: ((u64*)tablebase)[<IA[y:30]>], where y = (37-T*SZ)+26. That is, starting at bit "y" ending(inclusive) at bit30. For TTBR0*_EL1, y = 32, while for TTBR1_EL1 y = 35.
+
| 0x300
  Hence, for TTBR0, index=((vaddr>>30) & 0x7), and for TTBR1, index=((vaddr>>30) & 0x3f).
+
| TZRAM Identity RWX (for init)
 +
|-
 +
| 0x40020000
 +
| 0x40020000
 +
| 0x20000
 +
| 0x300
 +
| IRAM Identity RWX (for init)
 +
|-
 +
| 0x1F0080000
 +
| 0x50041000
 +
| 0x1000
 +
| 0x40000000000304
 +
| ARM Interrupt Distributor
 +
|-
 +
| 0x1F0082000
 +
| 0x50042000
 +
| 0x2000
 +
| 0x40000000000304
 +
| Interrupt Controller Physical CPU
 +
|-
 +
| 0x1F0085000
 +
| 0x70006000
 +
| 0x1000
 +
| 0x40000000000324
 +
| UART-A
 +
|-
 +
| 0x1F0087000
 +
| 0x60006000
 +
| 0x1000
 +
| 0x40000000000324
 +
| Clock and Reset
 +
|-
 +
| 0x1F0089000
 +
| 0x7000E000
 +
| 0x1000
 +
| 0x40000000000304
 +
| PMC
 +
|-
 +
| 0x1F008B000
 +
| 0x60005000
 +
| 0x1000
 +
| 0x40000000000304
 +
| Timers
 +
|-
 +
| 0x1F008D000
 +
| 0x6000C000
 +
| 0x1000
 +
| 0x40000000000304
 +
| System Registers
 +
|-
 +
| 0x1F008F000
 +
| 0x70012000
 +
| 0x2000
 +
| 0x40000000000304
 +
| Security Engine
 +
|-
 +
| 0x1F00AD000
 +
| 0x70412000
 +
| 0x2000
 +
| 0x40000000000304
 +
| Erista: Nothing Present, Mariko: Security Engine 2
 +
|-
 +
| 0x1F0092000
 +
| 0x700F0000
 +
| 0x1000
 +
| 0x40000000000304
 +
| SYSCTR0
 +
|-
 +
| 0x1F0094000
 +
| 0x70019000
 +
| 0x1000
 +
| 0x40000000000304
 +
| Memory Controller
 +
|-
 +
| 0x1F0096000
 +
| 0x7000F000
 +
| 0x1000
 +
| 0x40000000000304
 +
| Fuse Registers
 +
|-
 +
| 0x1F0098000
 +
| 0x70000000
 +
| 0x4000
 +
| 0x40000000000304
 +
| MISC Registers
 +
|-
 +
| 0x1F009D000
 +
| 0x60007000
 +
| 0x1000
 +
| 0x40000000000304
 +
| Flow Controller
 +
|-
 +
| 0x1F009F000
 +
| 0x40002000
 +
| 0x1000
 +
| 0x40000000000304
 +
| IRAM
 +
|-
 +
| 0x1F00A1000
 +
| 0x7000D000
 +
| 0x1000
 +
| 0x40000000000304
 +
| I2C-5
 +
|-
 +
| 0x1F00A3000
 +
| 0x6000D000
 +
| 0x1000
 +
| 0x40000000000304
 +
| GPIO-1
 +
|-
 +
| 0x1F00A5000
 +
| 0x7000C000
 +
| 0x1000
 +
| 0x40000000000304
 +
| I2C
 +
|-
 +
| 0x1F00A7000
 +
| 0x6000F000
 +
| 0x1000
 +
| 0x40000000000304
 +
| BPMP Exception Vectors
 +
|-
 +
| 0x1F00A9000
 +
| 0x7001C000
 +
| 0x1000
 +
| 0x40000000000304
 +
| MC0
 +
|-
 +
| 0x1F00AB000
 +
| 0x7001D000
 +
| 0x1000
 +
| 0x40000000000304
 +
| MC1
 +
|-
 +
| 0x1F0100000
 +
| 0x7C010000
 +
| 0x10000
 +
| 0x40000000000380
 +
| TZRAM (R-- for context save)
 +
|-
 +
| 0x1F0140000
 +
| 0x7C012000
 +
| 0x9000
 +
| 0x300
 +
| TZRAM (R-X .text)
 +
|-
 +
| 0x1F0149000
 +
| 0x7C01B000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (RW- .rodata)
 +
|-
 +
| 0x1F014A000
 +
| 0x7C01C000
 +
| 0x2000
 +
| 0x40000000000300
 +
| TZRAM (RW- .rwdata)
 +
|-
 +
| 0x1F01A0000
 +
| 0x40020000
 +
| 0x10000
 +
| 0x40000000000324
 +
| IRAM (RW- for context save)
 +
|-
 +
| 0x1F01B0000
 +
| 0x40003000
 +
| 0x1000
 +
| 0x40000000000324
 +
| IRAM (BPMP firmware destination)
 +
|-
 +
| 0x1F01C7000
 +
| 0x8000F000
 +
| 0x1000
 +
| 0x40000000000324
 +
| DRAM (SE Context Save destination)
 +
|-
 +
| 0x1F01E0000
 +
| 0x7C010000
 +
| 0x2000
 +
| 0x300
 +
| TZRAM (RWX pk2ldr for init)
 +
|-
 +
| 0x1F01F4000
 +
| X
 +
| 0x1000
 +
| 0x40000000000723
 +
| DRAM (SPL .bss buffer visible to the Security Engine)
 +
|-
 +
| 0x1F01F6000
 +
| 0x7C010000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (stacks)
 +
|-
 +
| 0x1F01F8000
 +
| 0x7C011000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (stacks)
 +
|-
 +
| 0x1F01FA000
 +
| 0x7C01D000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (stacks, warmboot crt0)
 +
|-
 +
| 0x1F01FC000
 +
| 0x7C01E000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (L2 Page Table)
 +
|-
 +
| 0x1F01FE000
 +
| 0x7C01F000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (L3 Page Table)
 +
|}
 +
 
 +
== [[6.0.0]] ==
 +
6.0.0 reduced the .rwdata segment to one page (previously 2).
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Vmem
 +
! Physmem
 +
! Size
 +
! Descriptor ORR-value
 +
! Description
 +
|-
 +
| 0x7C010000
 +
| 0x7C010000
 +
| 0x10000
 +
| 0x300
 +
| TZRAM Identity RWX (for init)
 +
|-
 +
| 0x40020000
 +
| 0x40020000
 +
| 0x20000
 +
| 0x300
 +
| IRAM Identity RWX (for init)
 +
|-
 +
| 0x1F0080000
 +
| 0x50041000
 +
| 0x1000
 +
| 0x40000000000304
 +
| ARM Interrupt Distributor
 +
|-
 +
| 0x1F0082000
 +
| 0x50042000
 +
| 0x2000
 +
| 0x40000000000304
 +
| Interrupt Controller Physical CPU
 +
|-
 +
| 0x1F0085000
 +
| 0x70006000
 +
| 0x1000
 +
| 0x40000000000324
 +
| UART-A
 +
|-
 +
| 0x1F0087000
 +
| 0x60006000
 +
| 0x1000
 +
| 0x40000000000324
 +
| Clock and Reset
 +
|-
 +
| 0x1F0089000
 +
| 0x7000E000
 +
| 0x1000
 +
| 0x40000000000304
 +
| PMC
 +
|-
 +
| 0x1F008B000
 +
| 0x60005000
 +
| 0x1000
 +
| 0x40000000000304
 +
| Timers
 +
|-
 +
| 0x1F008D000
 +
| 0x6000C000
 +
| 0x1000
 +
| 0x40000000000304
 +
| System Registers
 +
|-
 +
| 0x1F008F000
 +
| 0x70012000
 +
| 0x2000
 +
| 0x40000000000304
 +
| Security Engine
 +
|-
 +
| 0x1F00AD000
 +
| 0x70412000
 +
| 0x2000
 +
| 0x40000000000304
 +
| Erista: Nothing Present, Mariko: Security Engine 2
 +
|-
 +
| 0x1F0092000
 +
| 0x700F0000
 +
| 0x1000
 +
| 0x40000000000304
 +
| SYSCTR0
 +
|-
 +
| 0x1F0094000
 +
| 0x70019000
 +
| 0x1000
 +
| 0x40000000000304
 +
| Memory Controller
 +
|-
 +
| 0x1F0096000
 +
| 0x7000F000
 +
| 0x1000
 +
| 0x40000000000304
 +
| Fuse Registers
 +
|-
 +
| 0x1F0098000
 +
| 0x70000000
 +
| 0x4000
 +
| 0x40000000000304
 +
| MISC Registers
 +
|-
 +
| 0x1F009D000
 +
| 0x60007000
 +
| 0x1000
 +
| 0x40000000000304
 +
| Flow Controller
 +
|-
 +
| 0x1F009F000
 +
| 0x40002000
 +
| 0x1000
 +
| 0x40000000000304
 +
| IRAM
 +
|-
 +
| 0x1F00A1000
 +
| 0x7000D000
 +
| 0x1000
 +
| 0x40000000000304
 +
| I2C-5
 +
|-
 +
| 0x1F00A3000
 +
| 0x6000D000
 +
| 0x1000
 +
| 0x40000000000304
 +
| GPIO-1
 +
|-
 +
| 0x1F00A5000
 +
| 0x7000C000
 +
| 0x1000
 +
| 0x40000000000304
 +
| I2C
 +
|-
 +
| 0x1F00A7000
 +
| 0x6000F000
 +
| 0x1000
 +
| 0x40000000000304
 +
| BPMP Exception Vectors
 +
|-
 +
| 0x1F00A9000
 +
| 0x7001C000
 +
| 0x1000
 +
| 0x40000000000304
 +
| MC0
 +
|-
 +
| 0x1F00AB000
 +
| 0x7001D000
 +
| 0x1000
 +
| 0x40000000000304
 +
| MC1
 +
|-
 +
| 0x1F0100000
 +
| 0x7C010000
 +
| 0x10000
 +
| 0x40000000000380
 +
| TZRAM (R-- for context save)
 +
|-
 +
| 0x1F0140000
 +
| 0x7C012000
 +
| 0x9000
 +
| 0x300
 +
| TZRAM (R-X .text)
 +
|-
 +
| 0x1F0149000
 +
| 0x7C01B000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (RW- .rodata)
 +
|-
 +
| 0x1F014A000
 +
| 0x7C01C000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (RW- .rwdata)
 +
|-
 +
| 0x1F01A0000
 +
| 0x40020000
 +
| 0x10000
 +
| 0x40000000000324
 +
| IRAM (RW- for context save)
 +
|-
 +
| 0x1F01B0000
 +
| 0x40003000
 +
| 0x1000
 +
| 0x40000000000324
 +
| IRAM (BPMP firmware destination)
 +
|-
 +
| 0x1F01C7000
 +
| 0x8000F000
 +
| 0x1000
 +
| 0x40000000000324
 +
| DRAM (SE Context Save destination)
 +
|-
 +
| 0x1F01E0000
 +
| 0x7C010000
 +
| 0x2000
 +
| 0x300
 +
| TZRAM (RWX pk2ldr for init)
 +
|-
 +
| 0x1F01F4000
 +
| X
 +
| 0x1000
 +
| 0x40000000000723
 +
| DRAM (SPL .bss buffer visible to the Security Engine)
 +
|-
 +
| 0x1F01F6000
 +
| 0x7C010000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (stacks)
 +
|-
 +
| 0x1F01F8000
 +
| 0x7C011000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (stacks)
 +
|-
 +
| 0x1F01FA000
 +
| 0x7C01D000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (stacks, warmboot crt0)
 +
|-
 +
| 0x1F01FC000
 +
| 0x7C01E000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (L2 Page Table)
 +
|-
 +
| 0x1F01FE000
 +
| 0x7C01F000
 +
| 0x1000
 +
| 0x40000000000300
 +
| TZRAM (L3 Page Table)
 +
|}
 +
 
 +
= IRAM =
 +
== BIT ==
 +
During boot, the BootROM saves the [[BCT]] in IRAM at address 0x40000100 with Erista, and 0x40000464 with Mariko. The preceding 0x100 bytes (IRAM memory range from 0x40000000 to 0x40000100) contain a structure called BIT (Boot Info Table) which encapsulates the BCT in IRAM and is initialized by the BootROM as follows:
 +
 
 +
=== Erista ===
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Field
 +
!  Description
 +
|-
 +
|  0x00
 +
|  0x04
 +
|  BootRomVersion
 +
|  Set to 0x00210001 (BOOTDATA_VERSION_T210).
 +
|-
 +
|  0x04
 +
|  0x04
 +
|  DataVersion
 +
|  Set to 0x00210001 (BOOTDATA_VERSION_T210).
 +
|-
 +
|  0x08
 +
|  0x04
 +
|  RcmVersion
 +
|  Set to 0x00210001 (BOOTDATA_VERSION_T210).
 +
|-
 +
|  0x0C
 +
|  0x04
 +
|  BootType
 +
|
 +
None = 0
 +
Cold = 1
 +
Recovery = 2
 +
Uart = 3
 +
ExitRcm = 4
 +
|-
 +
|  0x10
 +
|  0x04
 +
|  PrimaryDevice
 +
|  Set to 0x05 (IROM) on coldboot.
 +
|-
 +
|  0x14
 +
|  0x04
 +
|  SecondaryDevice
 +
|  Set to 0x04 (SDMMC) on coldboot.
 +
|-
 +
|  0x18
 +
|  0x04*0x04
 +
|  BootTimeLog
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Field
 +
|-
 +
|  0x00
 +
|  0x04
 +
|  BootTimeLogInit
 +
|-
 +
|  0x04
 +
|  0x04
 +
|  BootTimeLogExit
 +
|-
 +
|  0x08
 +
|  0x04
 +
|  BootReadBctTickCnt
 +
|-
 +
|  0x0C
 +
|  0x04
 +
|  BootReadBLTickCnt
 +
|}
 +
|-
 +
|  0x28
 +
|  0x04
 +
|  OscFrequency
 +
|  Value from CLK_RST_CONTROLLER_OSC_CTRL.
 +
|-
 +
|  0x2C
 +
|  0x01
 +
|  DevInitialized
 +
|  Set to 1 after the boot device is initialized.
 +
|-
 +
|  0x2D
 +
|  0x01
 +
|  SdramInitialized
 +
|  Set to 1 after the SDRAM parameters are parsed.
 +
|-
 +
|  0x2E
 +
|  0x01
 +
|  ClearedForceRecovery
 +
|  Set to 1 if bit 2 was set in APBDEV_PMC_SCRATCH0.
 +
|-
 +
|  0x2F
 +
|  0x01
 +
|  ClearedFailBack
 +
|  Set to 1 if bit 4 was set in APBDEV_PMC_SCRATCH0.
 +
|-
 +
|  0x30
 +
|  0x01
 +
|  InvokedFailBack
 +
|  Set to 1 if the bootloaders have different versions in the BCT.
 +
|-
 +
|  0x31
 +
|  0x01
 +
|  IRomPatchStatus
 +
 +
|-
 +
|  0x32
 +
|  0x01
 +
|  BctValid
 +
|  Set to 1 if the BCT was parsed successfully.
 +
|-
 +
|  0x33
 +
|  0x09
 +
|  BctStatus
 +
|  Each bit contains the status for BCT reads in a given block.
 +
|-
 +
|  0x3C
 +
|  0x04
 +
|  BctLastJournalRead
 +
|  Contains the status of the last journal block read.
 +
None = 0
 +
Success = 1
 +
ValidationFailure = 2
 +
DeviceReadError = 3
 +
|-
 +
|  0x40
 +
|  0x04
 +
|  BctBlock
 +
|  Block number where the BCT was found.
 +
|-
 +
|  0x44
 +
|  0x04
 +
|  BctPage
 +
|  Page number where the BCT was found.
 +
|-
 +
|  0x48
 +
|  0x04
 +
|  BctSize
 +
|  Size of the BCT in IRAM (0x2800).  
 +
|-
 +
|  0x4C
 +
|  0x04
 +
|  BctPtr
 +
|  Pointer to the BCT in IRAM (0x40000100).
 +
|-
 +
|  0x50
 +
|  0x18*0x04
 +
|  BlState
 +
|  Contains the state of attempts to load each bootloader.
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Field
 +
|-
 +
|  0x00
 +
|  0x04
 +
|  Status
 +
|-
 +
|  0x04
 +
|  0x04
 +
|  FirstEccBlock
 +
|-
 +
|  0x08
 +
|  0x04
 +
|  FirstEccPage
 +
|-
 +
|  0x0C
 +
|  0x04
 +
|  FirstCorrectedEccBlock
 +
|-
 +
|  0x10
 +
|  0x04
 +
|  FirstCorrectedEccPage
 +
|-
 +
|  0x14
 +
|  0x01
 +
|  HadEccError
 +
|-
 +
|  0x15
 +
|  0x01
 +
|  HadCrcError
 +
|-
 +
|  0x16
 +
|  0x01
 +
|  HadCorrectedEccError
 +
|-
 +
|  0x17
 +
|  0x01
 +
|  UsedForEccRecovery
 +
|}
 +
|-
 +
|  0xB0
 +
|  0x3C
 +
|  SecondaryDevStatus
 +
|  Structure to hold secondary boot device status.
 +
For SDMMC, the following applies:
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Field
 +
|-
 +
|  0x00
 +
|  0x01
 +
|  FuseDataWidth
 +
|-
 +
|  0x01
 +
|  0x01
 +
|  FuseVoltageRange
 +
|-
 +
|  0x02
 +
|  0x01
 +
|  FuseDisableBootMode
 +
|-
 +
|  0x03
 +
|  0x01
 +
|  FuseDdrMode
 +
|-
 +
|  0x04
 +
|  0x01
 +
|  DiscoveredCardType
 +
|-
 +
|  0x05
 +
|  0x03
 +
|  Reserved
 +
|-
 +
|  0x08
 +
|  0x04
 +
|  DiscoveredVoltageRange
 +
|-
 +
|  0x0C
 +
|  0x01
 +
|  DataWidthUnderUse
 +
|-
 +
|  0x0D
 +
|  0x01
 +
|  PowerClassUnderUse
 +
|-
 +
|  0x0E
 +
|  0x01
 +
|  AutoCalStatus
 +
|-
 +
|  0x0F
 +
|  0x01
 +
|  Reserved
 +
|-
 +
|  0x10
 +
|  0x10
 +
|  Cid
 +
|-
 +
|  0x20
 +
|  0x04
 +
|  NumPagesRead
 +
|-
 +
|  0x24
 +
|  0x04
 +
|  NumCrcErrors
 +
|-
 +
|  0x25
 +
|  0x01
 +
|  BootFromBootPartition
 +
|-
 +
|  0x26
 +
|  0x01
 +
|  BootModeReadSuccessful
 +
|-
 +
|  0x27
 +
|  0x15
 +
|  Reserved
 +
|}
 +
|-
 +
|  0xEC
 +
|  0x04
 +
|  UsbChargingStatus
 +
 +
|-
 +
|  0xF0
 +
|  0x04
 +
|  SafeStartAddr
 +
|  Pointer to the end of the BCT in IRAM (0x40002900).
 +
|-
 +
|  0xF4
 +
|  0x0C
 +
|  Reserved
 +
|  Must be empty.
 +
|}
 +
 
 +
=== Mariko ===
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Field
 +
!  Description
 +
|-
 +
|  0x00
 +
|  0x04
 +
|  BootRomVersion
 +
|  Set to 0x00210001 (BOOTDATA_VERSION_T210).
 +
|-
 +
|  0x04
 +
|  0x04
 +
|  DataVersion
 +
|  Set to 0x00210001 (BOOTDATA_VERSION_T210).
 +
|-
 +
|  0x08
 +
|  0x04
 +
|  RcmVersion
 +
|  Set to 0x00210001 (BOOTDATA_VERSION_T210).
 +
|-
 +
|  0x0C
 +
|  0x04
 +
|  BootType
 +
|
 +
None = 0
 +
Cold = 1
 +
Recovery = 2
 +
Uart = 3
 +
ExitRcm = 4
 +
|-
 +
|  0x10
 +
|  0x04
 +
|  PrimaryDevice
 +
|  Set to 0x05 (IROM) on coldboot.  
 +
|-
 +
|  0x14
 +
|  0x04
 +
|  SecondaryDevice
 +
|  Set to 0x04 (SDMMC) on coldboot.
 +
|-
 +
|  0x18
 +
|  0x04
 +
|  AuthenticationScheme
 +
 +
|-
 +
|  0x1C
 +
|  0x01
 +
|  EncryptionEnabled
 +
 +
|-
 +
|  0x1D
 +
|  0x03
 +
|  Reserved
 +
 +
|-
 +
|  0x20
 +
|  0x04
 +
|  BootROMtracker
 +
 +
|-
 +
|  0x24
 +
|  0x05*0x04
 +
|  BootTimeLog
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Field
 +
|-
 +
|  0x00
 +
|  0x04
 +
|  BootTimeLogInit
 +
|-
 +
|  0x04
 +
|  0x04
 +
|  BootTimeLogExit
 +
|-
 +
|  0x08
 +
|  0x04
 +
|  BootSetupTickCnt
 +
|-
 +
|  0x0C
 +
|  0x04
 +
|  BootReadBctTickCnt
 +
|-
 +
|  0x10
 +
|  0x04
 +
|  BootReadBLTickCnt
 +
|}
 +
|-
 +
|  0x38
 +
|  0x10*0x28
 +
|  BootFlowLog
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Field
 +
|-
 +
|  0x00
 +
|  0x04
 +
|  BootFlowLogInit
 +
|-
 +
|  0x04
 +
|  0x04
 +
|  BootFlowLogExit
 +
|-
 +
|  0x08
 +
|  0x04
 +
|  BootFlowFuncId
 +
|-
 +
|  0x0C
 +
|  0x04
 +
|  BootFlowFuncStatus
 +
|}
 +
|-
 +
|  0x2B8
 +
|  0x04
 +
|  OscFrequency
 +
|  Value from CLK_RST_CONTROLLER_OSC_CTRL.
 +
|-
 +
|  0x2BC
 +
|  0x01
 +
|  DevInitialized
 +
|  Set to 1 after the boot device is initialized.
 +
|-
 +
|  0x2BD
 +
|  0x01
 +
|  SdramInitialized
 +
|  Set to 1 after the SDRAM parameters are parsed.
 +
|-
 +
|  0x2BE
 +
|  0x01
 +
|  ClearedForceRecovery
 +
|  Set to 1 if bit 2 was set in APBDEV_PMC_SCRATCH0.
 +
|-
 +
|  0x2BF
 +
|  0x01
 +
|  ClearedFailBack
 +
|  Set to 1 if bit 4 was set in APBDEV_PMC_SCRATCH0.
 +
|-
 +
|  0x2C0
 +
|  0x01
 +
|  InvokedFailBack
 +
|  Set to 1 if the bootloaders have different versions in the BCT.
 +
|-
 +
|  0x2C1
 +
|  0x01
 +
|  IRomPatchStatus
 +
 +
|-
 +
|  0x2C2
 +
|  0x01
 +
|  BctSizeValid
 +
 +
|-
 +
|  0x2C3
 +
|  0x09
 +
|  BctSizeStatus
 +
 +
|-
 +
|  0x2CC
 +
|  0x04
 +
|  BctSizeLastJournalRead
 +
 +
|-
 +
|  0x2D0
 +
|  0x04
 +
|  BctSizeBlock
 +
 +
|-
 +
|  0x2D4
 +
|  0x04
 +
|  BctSizePage
 +
 +
|-
 +
|  0x2D8
 +
|  0x01
 +
|  BctValid
 +
|  Set to 1 if the BCT was parsed successfully.
 +
|-
 +
|  0x2D9
 +
|  0x09
 +
|  BctStatus
 +
|  Each bit contains the status for BCT reads in a given block.
 +
|-
 +
|  0x2E2
 +
|  0x02
 +
|  Reserved
 +
 +
|-
 +
|  0x2E4
 +
|  0x04
 +
|  BctLastJournalRead
 +
|  Contains the status of the last journal block read.
 +
None = 0
 +
Success = 1
 +
ValidationFailure = 2
 +
DeviceReadError = 3
 +
|-
 +
|  0x2E8
 +
|  0x04
 +
|  BctBlock
 +
|  Block number where the BCT was found.
 +
|-
 +
|  0x2EC
 +
|  0x04
 +
|  BctPage
 +
|  Page number where the BCT was found.
 +
|-
 +
|  0x2F0
 +
|  0x04
 +
|  BctSize
 +
|  Size of the BCT in IRAM.
 +
|-
 +
|  0x2F4
 +
|  0x04
 +
|  BctPtr
 +
|  Pointer to the BCT in IRAM.  
 +
|-
 +
|  0x2F8
 +
|  0x18*0x04
 +
|  BlState
 +
|  Contains the state of attempts to load each bootloader.
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Offset
 +
!  Size
 +
!  Field
 +
|-
 +
|  0x00
 +
|  0x04
 +
|  Status
 +
|-
 +
|  0x04
 +
|  0x04
 +
|  FirstEccBlock
 +
|-
 +
|  0x08
 +
|  0x04
 +
|  FirstEccPage
 +
|-
 +
|  0x0C
 +
|  0x04
 +
|  FirstCorrectedEccBlock
 +
|-
 +
|  0x10
 +
|  0x04
 +
|  FirstCorrectedEccPage
 +
|-
 +
|  0x14
 +
|  0x01
 +
|  HadEccError
 +
|-
 +
|  0x15
 +
|  0x01
 +
|  HadCrcError
 +
|-
 +
|  0x16
 +
|  0x01
 +
|  HadCorrectedEccError
 +
|-
 +
|  0x17
 +
|  0x01
 +
|  UsedForEccRecovery
 +
|}
 +
|-
 +
|  0x358
 +
|  0x100
 +
|  SecondaryDevStatus
 +
|  Structure to hold secondary boot device status.
 +
|-
 +
|  0x458
 +
|  0x03
 +
|  Reserved
 +
 +
|-
 +
|  0x45B
 +
|  0x04
 +
|  UsbChargingStatus
 +
 +
|-
 +
|  0x45F
 +
|  0x01
 +
|  PmuBootSelReadError
 +
 +
|-
 +
|  0x460
 +
|  0x04
 +
|  SafeStartAddr
 +
|  Pointer to the end of the BCT in IRAM.
 +
|}
 +
 
 +
= Carveouts =
 +
The MC (Memory Controller) provides multiple configurable memory carveouts which allow to protect and limit access to sensitive DRAM regions. Carveouts work on the physical access level, thus acting as the last protection barrier from unauthorized memory accesses.
 +
 
 +
A total of 9 programmable carveouts are available from which 4 have a fixed function (TZDRAM, VPR, SEC and MTS) and 5 are generalized carevouts (GSCs 1 to 5).
 +
 
 +
== TZDRAM Carveout ==
 +
Defines a DRAM region that can only be accessed by TrustZone-secure clients. Currently unused by the Switch.
 +
 
 +
This carveout is controlled by the following MC registers:
 +
<pre>
 +
MC_SECURITY_CFG0
 +
MC_SECURITY_CFG1
 +
MC_SECURITY_CFG3
 +
</pre>
 +
 
 +
== VPR Carveout ==
 +
Defines a DRAM region that can only be accessed by clients that are part of the video decode and display process (Display, GPU, TSEC, VIC, NVENC, NVDEC and HDA). Currently unused by the Switch.
 +
 
 +
This carveout is controlled by the following MC registers:
 +
<pre>
 +
MC_VIDEO_PROTECT_GPU_OVERRIDE_0
 +
MC_VIDEO_PROTECT_GPU_OVERRIDE_1
 +
MC_VIDEO_PROTECT_BOM
 +
MC_VIDEO_PROTECT_SIZE_MB
 +
MC_VIDEO_PROTECT_REG_CTRL
 +
</pre>
 +
 
 +
== SEC Carveout ==
 +
Defines a DRAM region that can only be accessed by the [[#TSEC|TSEC]]. Deprecated and unused by the Switch.
 +
 
 +
This carveout is controlled by the following MC registers:
 +
<pre>
 +
MC_SEC_CARVEOUT_BOM
 +
MC_SEC_CARVEOUT_SIZE_MB
 +
MC_SEC_CARVEOUT_REG_CTRL
 +
</pre>
 +
 
 +
== MTS Carveout ==
 +
Defines a DRAM region for Falcon microcode. Deprecated and unused by the Switch.
 +
 
 +
This carveout is controlled by the following MC registers:
 +
<pre>
 +
MC_MTS_CARVEOUT_BOM
 +
MC_MTS_CARVEOUT_SIZE_MB
 +
MC_MTS_CARVEOUT_ADR_HI
 +
MC_MTS_CARVEOUT_REG_CTRL
 +
</pre>
 +
 
 +
== Generalized Carveouts ==
 +
These carveouts can be freely configured for any client that supports them.
 +
 
 +
These carveouts are controlled by the following MC registers:
 +
<pre>
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_BOM
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_BOM_HI
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_SIZE_128KB
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS0
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS1
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS2
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS3
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS4
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS0
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS1
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS2
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS3
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS4
 +
MC_SECURITY_CARVEOUT1/2/3/4/5_CFG0
 +
</pre>
 +
 
 +
The client access registers (CLIENT_ACCESS0/1/2/3/4) are used to whitelist accesses from MC clients as follows:
 +
{| class="wikitable" border="1"
 +
!  Bits
 +
!  ClientAccess0
 +
!  ClientAccess1
 +
!  ClientAccess2
 +
!  ClientAccess3
 +
!  ClientAccess4
 +
|-
 +
| 0
 +
| CSR_PTCR
 +
| Reserved
 +
| CSW_VDEMBEW
 +
| CSR_SDMMCRA
 +
| CSR_SESRD
 +
|-
 +
| 1
 +
| CSR_DISPLAY0A
 +
| Reserved
 +
| CSW_VDETPMW
 +
| CSR_SDMMCRAA
 +
| CSW_SESWR
 +
|-
 +
| 2
 +
| CSR_DISPLAY0AB
 +
| CSR_VDEBSEVR
 +
| Reserved
 +
| CSR_SDMMCR
 +
| CSR_AXIAPR
 +
|-
 +
| 3
 +
| CSR_DISPLAY0B
 +
| CSR_VDEMBER
 +
| Reserved
 +
| CSR_SDMMCRAB
 +
| CSW_AXIAPW
 +
|-
 +
| 4
 +
| CSR_DISPLAY0BB
 +
| CSR_VDEMCER
 +
| CSR_ISPRA
 +
| CSW_SDMMCWA
 +
| CSR_ETRR
 +
|-
 +
| 5
 +
| CSR_DISPLAY0C
 +
| CSR_VDETPER
 +
| Reserved
 +
| CSW_SDMMCWAA
 +
| CSW_ETRW
 +
|-
 +
| 6
 +
| CSR_DISPLAY0CB
 +
| CSR_MPCORELPR
 +
| CSW_ISPWA
 +
| CSW_SDMMCW
 +
| CSR_TSECSRDB
 +
|-
 +
| 7
 +
| Reserved
 +
| CSR_MPCORER
 +
| CSW_ISPWB
 +
| CSW_SDMMCWAB
 +
| CSW_TSECSWRB
 +
|-
 +
| 8
 +
| Reserved
 +
| Reserved
 +
| Reserved
 +
| Reserved
 +
| CSR_GPUSRD2
 +
|-
 +
| 9
 +
| Reserved
 +
| Reserved
 +
| Reserved
 +
| Reserved
 +
| CSW_GPUSWR2
 +
|-
 +
| 10
 +
| Reserved
 +
| Reserved
 +
| CSR_XUSB_HOSTR
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 11
 +
| Reserved
 +
| CSW_NVENCSWR
 +
| CSW_XUSB_HOSTW
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 12
 +
| Reserved
 +
| Reserved
 +
| CSR_XUSB_DEVR
 +
| CSR_VICSRD
 +
| Reserved
 +
|-
 +
| 13
 +
| Reserved
 +
| Reserved
 +
| CSW_XUSB_DEVW
 +
| CSW_VICSWR
 +
| Reserved
 +
|-
 +
| 14
 +
| CSR_AFIR
 +
| Reserved
 +
| CSR_ISPRAB (Erista) or CSR_SE2SRD (Mariko)
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 15
 +
| CSR_AVPCARM7R
 +
| Reserved
 +
| Reserved
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 16
 +
| CSR_DISPLAYHC
 +
| Reserved
 +
| CSW_ISPWAB (Erista) or CSW_SE2SWR (Mariko)
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 17
 +
| CSR_DISPLAYHCB
 +
| CSW_AFIW
 +
| CSW_ISPWBB (Erista) or Reserved (Mariko)
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 18
 +
| Reserved
 +
| CSW_AVPCARM7W
 +
| Reserved
 +
| CSW_VIW
 +
| Reserved
 +
|-
 +
| 19
 +
| Reserved
 +
| Reserved
 +
| Reserved
 +
| CSR_DISPLAYD
 +
| Reserved
 +
|-
 +
| 20
 +
| Reserved
 +
| Reserved
 +
| CSR_TSECSRD
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 21
 +
| CSR_HDAR
 +
| CSW_HDAW
 +
| CSW_TSECSWR
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 22
 +
| CSR_HOST1XDMAR
 +
| CSW_HOST1XW
 +
| CSR_A9AVPSCR
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 23
 +
| CSR_HOST1XR
 +
| Reserved
 +
| CSW_A9AVPSCW
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 24
 +
| Reserved
 +
| CSW_MPCORELPW
 +
| CSR_GPUSRD
 +
| CSR_NVDECSRD
 +
| Reserved
 +
|-
 +
| 25
 +
| Reserved
 +
| CSW_MPCOREW
 +
| CSW_GPUSWR
 +
| CSW_NVDECSWR
 +
| Reserved
 +
|-
 +
| 26
 +
| Reserved
 +
| Reserved
 +
| CSR_DISPLAYT
 +
| CSR_APER
 +
| Reserved
 +
|-
 +
| 27
 +
| Reserved
 +
| CSW_PPCSAHBDMAW
 +
| Reserved
 +
| CSW_APEW
 +
| Reserved
 +
|-
 +
| 28
 +
| CSR_NVENCSRD
 +
| CSW_PPCSAHBSLVW
 +
| Reserved
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 29
 +
| CSR_PPCSAHBDMAR
 +
| CSW_SATAW
 +
| Reserved
 +
| Reserved
 +
| Reserved
 +
|-
 +
| 30
 +
| CSR_PPCSAHBSLVR
 +
| CSW_VDEBSEVW
 +
| Reserved
 +
| CSR_NVJPGSRD
 +
| Reserved
 +
|-
 +
| 31
 +
| CSR_SATAR
 +
| CSW_VDEDBGW
 +
| Reserved
 +
| CSW_NVJPGSWR
 +
| Reserved
 +
|}
 +
 
 +
The configuration register (CFG0) is used to control the carveout's properties as follows:
 +
{| class="wikitable" border="1"
 +
!  Bits
 +
!  Description
 +
|-
 +
| 0
 +
| PROTECT_MODE
 +
0: LOCKBIT_SECURE (registers cannot be modified after lock down)
 +
1: TZ_SECURE (registers can be modified by TZ after lock down)
 +
|-
 +
| 1
 +
| LOCK_MODE
 +
0: UNLOCKED (registers can be modified at any time)
 +
1: LOCKED (registers cannot be modified until reset)
 +
|-
 +
| 2
 +
| ADDRESS_TYPE
 +
0: ANY_ADDRESS
 +
1: UNTRANSLATED_ONLY
 +
|-
 +
| 3-6
 +
| READ_ACCESS_LEVEL
 +
Bit 0: Access level 0 (default for all clients)
 +
Bit 1: Access level 1 (unknown)
 +
Bit 2: Access level 2 (Falcon clients in LS mode)
 +
Bit 3: Access level 3 (Falcon clients in HS mode)
 +
|-
 +
| 7-10
 +
| WRITE_ACCESS_LEVEL
 +
Bit 0: Access level 0 (default for all clients)
 +
Bit 1: Access level 1 (unknown)
 +
Bit 2: Access level 2 (Falcon clients in LS mode)
 +
Bit 3: Access level 3 (Falcon clients in HS mode)
 +
|-
 +
| 11-13
 +
| APERTURE_ID
 +
|-
 +
| 14-17
 +
| DISABLE_READ_CHECK_ACCESS_LEVEL
 +
Bit 0: Disable read access level 0 check
 +
Bit 1: Disable read access level 1 check
 +
Bit 2: Disable read access level 2 check
 +
Bit 3: Disable read access level 3 check
 +
|-
 +
| 18-21
 +
| DISABLE_WRITE_CHECK_ACCESS_LEVEL
 +
Bit 0: Disable write access level 0 check
 +
Bit 1: Disable write access level 1 check
 +
Bit 2: Disable write access level 2 check
 +
Bit 3: Disable write access level 3 check
 +
|-
 +
| 22
 +
| SEND_CFG_TO_GPU
 +
0: DISABLED
 +
1: ENABLED
 +
|-
 +
| 23
 +
| TZ_GLOBAL_WR_EN
 +
0: DISABLED
 +
1: BYPASS_CHECK
 +
|-
 +
| 24
 +
| TZ_GLOBAL_RD_EN
 +
0: DISABLED
 +
1: BYPASS_CHECK
 +
|-
 +
| 25
 +
| ALLOW_APERTURE_ID_MISMATCH
 +
0: DISABLED
 +
1: ENABLED
 +
|-
 +
| 26
 +
| FORCE_APERTURE_ID_MATCH
 +
0: DISABLED
 +
1: ENABLED
 +
|-
 +
| 27
 +
| IS_WPR
 +
0: DISABLED
 +
1: ENABLED
 +
|}
 +
 
 +
=== GSC1 ===
 +
This carveout is, by default, for NVDEC. In the Switch's case, this carveout is not used.
 +
 
 +
It is configured as follows:
 +
<pre>
 +
*(u32 *)MC_SECURITY_CARVEOUT1_BOM = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_BOM_HI = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_SIZE_128KB = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT1_CFG0 = 0x4000006;
 +
</pre>
 +
 
 +
=== GSC2 ===
 +
This carveout is, by default and in the Switch's case, for the GPU (WPR1).
 +
 
 +
It is configured as follows:
 +
<pre>
 +
*(u32 *)MC_SECURITY_CARVEOUT2_BOM = 0x80020000;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_BOM_HI = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_SIZE_128KB = 2;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 = 0x3000000;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 = 0x300;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT2_CFG0 = 0x440167E;
 +
</pre>
 +
 
 +
=== GSC3 ===
 +
This carveout is, by default, for the GPU (WPR2). In the Switch's case, this carveout is not used.
 +
 
 +
It is configured as follows:
 +
<pre>
 +
*(u32 *)MC_SECURITY_CARVEOUT3_BOM = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_BOM_HI = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_SIZE_128KB = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 = 0x3000000;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 = 0x300;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT3_CFG0 = 0x4401E7E;
 +
</pre>
 +
 
 +
=== GSC4 ===
 +
This carveout is, by default, for TSECA. In the Switch's case, this carveout is used by the Kernel.
 +
 
 +
It is initially configured as follows:
 +
<pre>
 +
*(u32 *)MC_SECURITY_CARVEOUT4_BOM = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_BOM_HI = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_SIZE_128KB = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT4_CFG0 = 0x8F;
 +
</pre>
  
"Vector Base Address Register (EL1)" = 0xfffffff7ffc50800.
+
Then further configured using [[SMC#ConfigureCarveout|smcConfigureCarveout]].
  
The table for TTBR0 only contains the following:
+
=== GSC5 ===
* Vmem 0x80000000 is mapped to physmem 0x80000000, using a size loaded from a register. This is only done when: "endaddr = 0x7fffffff + size; if(endaddr >= 0x80000001){...}"
+
This carveout is, by default, for TSECB. In the Switch's case, this carveout is used by the Kernel.
** The size is loaded from: "(u32 *0x70019050 & 0x3fff) << 20;"
 
** The value written to the MMU-table descriptor is: "physaddr | val | 0x709;". val is 1<<52 when "tmp>>34" is non-zero and when "if((physaddr & 0x3c0000000) == 0)", otherwise val=0. tmp=size at the start and increased by 0xffffffffc0000000 each loop iteration. physaddr is increased by 0x40000000 each loop iteration.
 
  
TTBR1:
+
It is initially configured as follows:
* vmem 0xFFFFFFF800000000 is mapped to physmem 0x80000000. Similar to above, except tmp=0 due to wrap-around, etc. The chunksize used when increasing addr is 0xfffffff840000000, with another +=0x40000000 separate from the addr cmp for the loop.
+
<pre>
** "endaddr = 0x3fffffff + (<size from above> | 0xfffffff800000000); enaddr = (endaddr & 0xffffffffc0000000)-1; if(endaddr >= 0xfffffff800000001){<map mem>}"
+
*(u32 *)MC_SECURITY_CARVEOUT5_BOM = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_BOM_HI = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_SIZE_128KB = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
 +
*(u32 *)MC_SECURITY_CARVEOUT5_CFG0 = 0x8F;
 +
</pre>
  
* Initializes level2 pagetable descriptor for vmem 0xFFFFFFF7C0000000. descriptor = 0x3 | physaddr. physaddr is core-specific.
+
Then further configured using [[SMC#ConfigureCarveout|smcConfigureCarveout]].
* Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FFC00000. descriptor = 0x3 | physaddr. physaddr is core-specific.
 
* The content of the pagetable for the following level3 mmutables are not initialized in the main mmutable-init func. descriptor = 0x8007c003(0x3 | <physaddr tablebase>). tablebase=0x8007c000.
 
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FEE00000. physaddr = tablebase + (0x1<<12).
 
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF000000. physaddr = tablebase + (0x2<<12).
 
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF200000. physaddr = tablebase + (0x3<<12).
 
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FFA00000. physaddr = tablebase + (0x7<<12).
 
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FEC00000. physaddr = tablebase.
 
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF400000. physaddr = tablebase + (0x4<<12).
 
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF600000. physaddr = tablebase + (0x5<<12).
 
** Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF800000. physaddr = tablebase + (0x6<<12).
 

Latest revision as of 18:06, 31 July 2024

Userspace

The userspace virtual address space can be either 32 or 36 bits. [2.0.0+] introduced support for 38 bit address spaces.

There are two regions randomized and enforced by the kernel, each one with upper bits random and 2MB-aligned:

  • ReservedHeapRegion, available from SVC#svcGetInfo.
  • ReservedMapRegion, available from SVC#svcGetInfo.
  • [2.0.0+] NewReservedMapRegion, available from SVC#svcGetInfo.
  • [2.0.0+] TlsIoRegion, not available to userspace.

The main binary is placed at an address that is provided to the kernel by Loader via SVC#svcCreateProcess.

Typically on 2.0.0+ systems, the main binary region has randomness in bits 37-21.

For the stack mapping region, the userland randomizes a page-offset where to start inside the region. This adds some additional entropy.

Binaries mapped by RO are mapped randomly everywhere in the entire address space. The base address for each NRO has all bits randomized and are 4K-aligned. This means that typically, on 2.0.0+ systems, bits 37-12 of the NRO base address are random.

For all binaries(main area / NROs), the R-- section is always located immediately after R-X. The RW- section is always located immediately after the R-- section. Hence, there's no extra randomization / guard-pages for these sections.

On version 1.0.0, the initial binaries loaded into memory by the kernel always have the upper 32-bits as all-zero, so there are 6 fewer bits of layout randomization.

Binaries loaded within the main-binary-region are loaded into memory in the following order, immediately after each other, for the binaries which exist in ExeFS:

  • rtld
  • main
  • subsdk*
  • sdk

ASLR Implementation

The kernel uses a MT19937 random number generator, seeded by smcGenerateRandomBytes.

1.0.0

if (AddressSpaceType == 2) {
  BaseAddr = 0x80000000; // 64-bit
  RandomMax = 0x6400;
}
else {
  BaseAddr = 0x40000000; // 32-bit
  RandomMax = 0x200;
}

if (AddressSpaceType == 4) {
  MapRegionSize = 0;
  HeapRegionSize = 0x80000000;
}
else {
  MapRegionSize = 0x40000000;
  HeapRegionSize = 0x40000000;
}

if (EnableAslr) {
  rnd0 = GetRandomRange(0, RandomMax) << 21;
  rnd1 = GetRandomRange(0, RandomMax) << 21;
}
else {
  rnd0 = rnd1 = 0;
}

this->MapBaseAddr = BaseAddr + min(rnd0, rnd1)
this->HeapRegionBaseAddr = this->MapBaseAddr + MapRegionSize + max(rnd0, rnd1) - min(rnd0, rnd1)

Kernel

For more details, see #Notes. Here comes a summary.

PXN bit is set in the MMU descriptor for userland code pages. This means that userland code pages are not executable in kernel mode (this is equivalent to SMEP on x86).

For userland pages, the kernel has same access as userland (either both are read-only or both are read-write). It does not have SMAP. The previous rule has one exception: pages that are mapped unreadable in usermode are still forced readable from kernelmode.

KASLR is being used since 5.0.0, but not before, with the following pseudocode (might contains some errors):

DRAM crt0 mapping (ttbr1): offsets DRAM with (rand64ViaSmc() % 0x3FFF0 << 21), allocates exactly (end - _start) + 1GB.
This is a "linear" mapping. Permissions are set properly.

KERN_ADDRSPACE       := [VA(_start) : min(0xFFFFFFFFFFE00000 - VA(_start), 0x40000000)]
DRAM_FROM_SECTION1   := DRAM[0x808cd000:] // 0x808cd000 corresponds to start of section1 (loaded INI1) data, reused later

/* Global Randomize range: 0xFFFFFF8000000000 to 0xFFFFFFFFFFE00000. */
/*
    Randomize picks a random integer in ranges, clears as many low bits required,
    then checks if the address is acceptable, if not it attempts to iterate through page table entries.
    
    If it doesn't find anything, it picks another integer. In case of general failure, the whole operation
    may be done from the start again (maybe ?).
*/

/* Core0 executes this big KASLR function, then powers on the other CPUs (?). */
MapPartially(RandomizeL1Boundary(DRAM, sizeof(DRAM)) -> DRAM_FROM_SECTION1: offsetof DRAM_FROM_SECTION1,

/* Randomize */
KERN_ADDRSPACE {
    Randomize(IOAndInitialStacks, 0x2000000) {
        Map(Randomize(UartA, 0x1000)) -> UartA,
        GuardPage,
        Map(Randomize(Gicd, 0x1000)) -> Gicd,
        GuardPage,
        Map(Randomize(Gicc, 0x1000)) -> Gicc,
        ForEachCore {
            GuardPage,
            Map(Randomize(EntryThreadStack, 0x1000)) -> NextFreePage(),
            GuardPage,
            Map(Randomize(IdleSchedulerThreadStack, 0x1000)) -> NextFreePage(),
            GuardPage,
            Map(Randomize(EL1AbortStack, 0x1000)) -> NextFreePage(),
        }
    },
    
    Randomize(KernelStacks, 0xE00000),
    Map(Randomize(SlabHeaps, 0x7E9000, AFTER(VA(_end)) -> PA(_end)),
    Randomize(Kip1DecompressionBuffer, 0x8000000), /* 128 MB VA range */
},

Map(RandomizePageBoundary(GuardPage + KCoreContext * 4)) -> NextFreePages(4)

1.0.0

Virtual Physical Size Attributes Permissions Description
0xFFFFFFFFBFC00000-0xFFFFFFFFBFC45FFF 0x800A0000 0x46000 0x78B R-X Kernel .text
0xFFFFFFFFBFC46000-0xFFFFFFFFBFC48FFF 0x800E6000 0x3000 0x6000000000078B R-- Kernel .rodata
0xFFFFFFFFBFC49000-0xFFFFFFFFBFC4FFFF 0x800E9000 0x7000 0x6000000000070B RW- Kernel .data+.bss
0xFFFFFFFFBFD72000-0xFFFFFFFFBFD72FFF 0x6000F000 0x1000 0x60000000000607 RW- Exception vectors
0xFFFFFFFFBFDB5000-0xFFFFFFFFBFDB5FFF 0x60007000 0x1000 0x60000000000607 RW- Flow controller
0xFFFFFFFFBFDB7000-0xFFFFFFFFBFDB7FFF 0x60004000 0x1000 0x60000000000607 RW- Primary ICTLR
0xFFFFFFFFBFDB9000-0xFFFFFFFFBFDB9FFF 0x60001000 0x1000 0x60000000000607 RW- Resource Semaphore
0xFFFFFFFFBFDBB000-0xFFFFFFFFBFDBBFFF 0x70016000 0x2000 0x60000000000607 RW- ATOMICS
0xFFFFFFFFBFDBE000-0xFFFFFFFFBFDBEFFF 0x7000E000 0x1000 0x60000000000607 RW- PMC
0xFFFFFFFFBFDC0000-0xFFFFFFFFBFDC0FFF 0x60006000 0x1000 0x60000000000607 RW- Clock and reset
0xFFFFFFFFBFDC2000-0xFFFFFFFFBFDC2FFF 0x7001D000 0x1000 0x60000000000607 RW- MC1
0xFFFFFFFFBFDC4000-0xFFFFFFFFBFDC4FFF 0x7001C000 0x1000 0x60000000000607 RW- MC0
0xFFFFFFFFBFDC6000-0xFFFFFFFFBFDC6FFF 0x70019000 0x1000 0x60000000000607 RW- MC
0xFFFFFFFFBFDC8000-0xFFFFFFFFBFDC8FFF 0x70006000 0x1000 0x60000000000607 RW- UART-A
0xFFFFFFFFBFDCA000-0xFFFFFFFFBFDCBFFF 0x80060000 0x2000 0x6000000000070B RW-
0xFFFFFFFFBFDCE000-0xFFFFFFFFBFDCFFFF 0x80068000 0x2000 0x6000000000070B RW- Kernel main stack (cpu0)
0xFFFFFFFFBFDD2000-0xFFFFFFFFBFDD2FFF 0x80070000 0x1000 0x6000000000070B RW- Kernel runner stack (cpu0)
0xFFFFFFFFBFDD4000-0xFFFFFFFFBFDD5FFF 0x80062000 0x2000 0x6000000000070B RW-
0xFFFFFFFFBFDD8000-0xFFFFFFFFBFDD9FFF 0x8006A000 0x2000 0x6000000000070B RW- Kernel main stack (cpu1)
0xFFFFFFFFBFDDC000-0xFFFFFFFFBFDDCFFF 0x80071000 0x1000 0x6000000000070B RW- Kernel runner stack (cpu1)
0xFFFFFFFFBFDDE000-0xFFFFFFFFBFDDFFFF 0x80064000 0x2000 0x6000000000070B RW-
0xFFFFFFFFBFDE2000-0xFFFFFFFFBFDE3FFF 0x8006C000 0x2000 0x6000000000070B RW- Kernel main stack (cpu2)
0xFFFFFFFFBFDE6000-0xFFFFFFFFBFDE6FFF 0x80072000 0x1000 0x6000000000070B RW- Kernel runner stack (cpu2)
0xFFFFFFFFBFDE8000-0xFFFFFFFFBFDE9FFF 0x80066000 0x2000 0x6000000000070B RW-
0xFFFFFFFFBFDEC000-0xFFFFFFFFBFDEDFFF 0x8006E000 0x2000 0x6000000000070B RW- Kernel main stack (cpu3)
0xFFFFFFFFBFDF0000-0xFFFFFFFFBFDF0FFF 0x80073000 0x1000 0x6000000000070B RW- Kernel runner stack (cpu3)
0xFFFFFFFFBFDFB000-0xFFFFFFFFBFDFBFFF 0x50041000 0x1000 0x60000000000607 RW- ARM Interrupt Distributor
0xFFFFFFFFBFDFD000-0xFFFFFFFFBFDFDFFF 0x50042000 0x1000 0x60000000000607 RW- Interrupt Controller Physical CPU interface
0xFFFFFFFFBFDF2000-0xFFFFFFFFBFDF3FFF 0x80060000+(cpuid*0x2000) 0x2000 0x6000000000070B RW-
0xFFFFFFFFBFDF6000-0xFFFFFFFFBFDF7FFF 0x80068000+(cpuid*0x2000) 0x2000 0x6000000000070B RW- Kernel main stack (per-core self-mirror)
0xFFFFFFFFBFDFF000-0xFFFFFFFFBFDFFFFF 0x80084000+(cpuid*0x1000) 0x1000 0x6000000000070B RW- Kernel runner stack (per-core self-mirror)
0xFFFFFFFE00000000-... 0x80000000 ... 0x60000000000709 RW- Raw DRAM access

2.0.0

Cores Virtual Physical Size Attributes Permissions Description
All 0xFFFFFFF7FFC00000-0xFFFFFFF7FFC62FFF 0x800A0000 0x63000 0x78B R-X Kernel .text
All 0xFFFFFFF7FFC63000-0xFFFFFFF7FFC65FFF 0x80103000 0x3000 0x6000000000078B R-- Kernel .rodata
All 0xFFFFFFF7FFC66000-0xFFFFFFF7FFC6EFFF 0x80106000 0x9000 0x6000000000070B RW- Kernel .data+.bss
All 0xFFFFFFF7FFDC0000-0xFFFFFFF7FFDC0FFF 0x60006000 0x1000 0x60000000000607 RW- Clock and Reset
All 0xFFFFFFF7FFDC2000-0xFFFFFFF7FFDC2FFF 0x7001D000 0x1000 0x60000000000607 RW- MC1
All 0xFFFFFFF7FFDC4000-0xFFFFFFF7FFDC4FFF 0x7001C000 0x1000 0x60000000000607 RW- MC0
All 0xFFFFFFF7FFDC6000-0xFFFFFFF7FFDC6FFF 0x70019000 0x1000 0x60000000000607 RW- MC
All 0xFFFFFFF7FFDC8000-0xFFFFFFF7FFDC8FFF 0x70006000 0x1000 0x60000000000607 RW- UART-A
All 0xFFFFFFF7FFDCA000-0xFFFFFFF7FFDCAFFF 0x80060000 0x2000 0x6000000000070B RW-
All 0xFFFFFFF7FFDCE000-0xFFFFFFF7FFDCEFFF 0x80068000 0x2000 0x6000000000070B RW-
All 0xFFFFFFF7FFDD2000-0xFFFFFFF7FFDD2FFF 0x80070000 0x1000 0x6000000000070B RW-
All 0xFFFFFFF7FFDD4000-0xFFFFFFF7FFDD4FFF 0x80062000 0x2000 0x6000000000070B RW-
All 0xFFFFFFF7FFDD8000-0xFFFFFFF7FFDD8FFF 0x8006A000 0x2000 0x6000000000070B RW-
All 0xFFFFFFF7FFDDC000-0xFFFFFFF7FFDDCFFF 0x80071000 0x1000 0x6000000000070B RW-
All 0xFFFFFFF7FFDDE000-0xFFFFFFF7FFDDEFFF 0x80064000 0x2000 0x6000000000070B RW-
All 0xFFFFFFF7FFDE2000-0xFFFFFFF7FFDE2FFF 0x8006C000 0x2000 0x6000000000070B RW-
All 0xFFFFFFF7FFDE6000-0xFFFFFFF7FFDE6FFF 0x80072000 0x1000 0x6000000000070B RW-
All 0xFFFFFFF7FFDE8000-0xFFFFFFF7FFDE8FFF 0x80066000 0x2000 0x6000000000070B RW-
All 0xFFFFFFF7FFDEC000-0xFFFFFFF7FFDECFFF 0x8006E000 0x2000 0x6000000000070B RW-
All 0xFFFFFFF7FFDF0000-0xFFFFFFF7FFDF0FFF 0x80073000 0x1000 0x6000000000070B RW-
All 0xFFFFFFF7FFDFB000-0xFFFFFFF7FFDFBFFF 0x50041000 0x1000 0x60000000000607 RW- ARM Interrupt Distributor
All 0xFFFFFFF7FFDFD000-0xFFFFFFF7FFDFDFFF 0x50042000 0x1000 0x60000000000607 RW- Interrupt Controller Physical CPU interface
All 0xFFFFFFF800000000-... 0x80000000 ... 0x60000000000709 RW- Raw DRAM access

3.0.0

Cores Virtual Physical Size Attributes Permissions Description
All 0xFFFFFFF7FFC00000-0xFFFFFFF7FFC4AFFF 0x800A0000 0x4B000 0x78B R-X Kernel .text
All 0xFFFFFFF7FFC4B000-0xFFFFFFF7FFC4DFFF 0x800EB000 0x3000 0x6000000000078B R-- Kernel .rodata
All 0xFFFFFFF7FFC4E000-0xFFFFFFF7FFC5AFFF 0x800EE000 0xD000 0x6000000000070B RW- Kernel .data+.bss
All 0xFFFFFFF7FFDAC000-0xFFFFFFF7FFDACFFF 0x60006000 0x1000 0x60000000000607 RW- Clock and Reset
All 0xFFFFFFF7FFDAE000-0xFFFFFFF7FFDAEFFF 0x7001D000 0x1000 0x60000000000607 RW- MC1
All 0xFFFFFFF7FFDB0000-0xFFFFFFF7FFDB0FFF 0x7001C000 0x1000 0x60000000000607 RW- MC0
All 0xFFFFFFF7FFDB2000-0xFFFFFFF7FFDB2FFF 0x70019000 0x1000 0x60000000000607 RW- MC
All 0xFFFFFFF7FFDB4000-0xFFFFFFF7FFDB4FFF 0x70006000 0x1000 0x60000000000607 RW- UART-A
All 0xFFFFFFF7FFDFB000-0xFFFFFFF7FFDFBFFF 0x50041000 0x1000 0x60000000000607 RW- ARM Interrupt Distributor
All 0xFFFFFFF7FFDFD000-0xFFFFFFF7FFDFDFFF 0x50042000 0x1000 0x60000000000607 RW- Interrupt Controller Physical CPU interface

4.0.0

Cores Virtual Physical Size Attributes Permissions Description
All 0xFFFFFFF7FFC00000-0xFFFFFFF7FFC50FFF 0x800A0000 0x51000 0x4000000000078B R-X Kernel .text
All 0xFFFFFFF7FFC51000-0xFFFFFFF7FFC53FFF 0x800F1000 0x3000 0x6000000000078B R-- Kernel .rodata
All 0xFFFFFFF7FFC54000-0xFFFFFFF7FFC61FFF 0x800F4000 0xE000 0x6000000000070B RW- Kernel .data+.bss
All 0xFFFFFFF7FFDAC000-0xFFFFFFF7FFDACFFF 0x60006000 0x1000 0x60000000000607 RW- Clock and Reset
All 0xFFFFFFF7FFDAE000-0xFFFFFFF7FFDAEFFF 0x7001D000 0x1000 0x60000000000607 RW- MC1
All 0xFFFFFFF7FFDB0000-0xFFFFFFF7FFDB0FFF 0x7001C000 0x1000 0x60000000000607 RW- MC0
All 0xFFFFFFF7FFDB2000-0xFFFFFFF7FFDB2FFF 0x70019000 0x1000 0x60000000000607 RW- MC
All 0xFFFFFFF7FFDB4000-0xFFFFFFF7FFDB4FFF 0x70006000 0x1000 0x60000000000607 RW- UART-A
All 0xFFFFFFF7FFDFB000-0xFFFFFFF7FFDFBFFF 0x50041000 0x1000 0x60000000000607 RW- ARM Interrupt Distributor
All 0xFFFFFFF7FFDFD000-0xFFFFFFF7FFDFDFFF 0x50042000 0x1000 0x60000000000607 RW- Interrupt Controller Physical CPU interface

The rest are are mapped to core-specific physaddrs, each one is 0x1000-bytes. Descriptor ORR-value = 0x6000000000070B.

Vmem Physmem
0xFFFFFFF7FFDF7000 <physaddr from vmem 0xFFFFFFF7FFDF6000> + 0x1000
0xFFFFFFF7FFDF3000 <physaddr from vmem 0xFFFFFFF7FFDF2000> + 0x1000
0xFFFFFFF7FFDF6000 0x800XX000
0xFFFFFFF7FFDF2000 0x800XX000
0xFFFFFFF7FFDFF000 0x800XX000
0xFFFFFFF7FFDF9000 0x800XX000

Notes

2.0.0

 Granule size for TTBR0*_EL1 is 4KB.
 TTBR0_EL1 vmem starts at vaddr 0x0.
 vmem end-addr for TTBR1_EL1 is 0xffffffffffffffff. vmem start-addr for TTBR1_EL1 is 0xFFFFFFF000000000.
 T0SZ = 31. Hence, bit-size of the TTBR0*_EL1 vmem region is 33. (0x0000000200000000)
 T1SZ = 28. Hence, bit-size of the TTBR1*_EL1 vmem region is 36. (0x0000001000000000)
 
 Note: ARM config for TTBR0 is presumably configured for userland later.
 
 See arm-doc for "Table D4-25 Translation table entry addresses when using the 4KB translation granule".
 
 See arm-doc for "Overview of VMSAv8-64 address translation using the 4KB translation granule".
 
 See arm-doc for "Table D4-11 TCR.TnSZ values and IA ranges, 4K granule with no concatenation of tables".
 Both TTBR*_EL1 use "Initial lookup level" 1. Therefore, the TTBR*_EL1 tables are level1.
 
 Due to T*SZ, Stage1/Stage2 translation for the initial table(level1) are the same, except Stage2 uses hard-coded T0SZ.
 Basically, the table is accessed as: ((u64*)tablebase)[<IA[y:30]>], where y = (37-T*SZ)+26. That is, starting at bit "y" ending(inclusive) at bit30. For TTBR0*_EL1, y = 32, while for TTBR1_EL1 y = 35.
 Hence, for TTBR0, index=((vaddr>>30) & 0x7), and for TTBR1, index=((vaddr>>30) & 0x3f).

"Vector Base Address Register (EL1)" = 0xfffffff7ffc50800.

The table for TTBR0 only contains the following:

  • Vmem 0x80000000 is mapped to physmem 0x80000000, using a size loaded from a register. This is only done when: "endaddr = 0x7fffffff + size; if(endaddr >= 0x80000001){...}"
    • The size is loaded from: "(u32 *0x70019050 & 0x3fff) << 20;"
    • The value written to the MMU-table descriptor is: "physaddr | val | 0x709;". val is 1<<52 when "tmp>>34" is non-zero and when "if((physaddr & 0x3c0000000) == 0)", otherwise val=0. tmp=size at the start and increased by 0xffffffffc0000000 each loop iteration. physaddr is increased by 0x40000000 each loop iteration.

TTBR1:

  • vmem 0xFFFFFFF800000000 is mapped to physmem 0x80000000. Similar to above, except tmp=0 due to wrap-around, etc. This also has usermode/kernel XN enabled in the descriptor ORR-value. The chunksize used when increasing addr is 0xfffffff840000000, with another +=0x40000000 separate from the addr cmp for the loop.
    • "endaddr = 0x3fffffff + (<size from above> | 0xfffffff800000000); enaddr = (endaddr & 0xffffffffc0000000)-1; if(endaddr >= 0xfffffff800000001){<map mem>}"
  • Initializes level2 pagetable descriptor for vmem 0xFFFFFFF7C0000000. descriptor = 0x3 | physaddr. physaddr is core-specific.
  • Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FFC00000. descriptor = 0x3 | physaddr. physaddr is core-specific.
  • The content of the pagetable for the following level3 mmutables are not initialized in the main mmutable-init func. descriptor = 0x8007c003(0x3 | <physaddr tablebase>). tablebase=0x8007c000.
    • Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FEE00000. physaddr = tablebase + (0x1<<12).
    • Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF000000. physaddr = tablebase + (0x2<<12).
    • Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF200000. physaddr = tablebase + (0x3<<12).
    • Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FFA00000. physaddr = tablebase + (0x7<<12).
    • Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FEC00000. physaddr = tablebase.
    • Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF400000. physaddr = tablebase + (0x4<<12).
    • Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF600000. physaddr = tablebase + (0x5<<12).
    • Initializes level3 pagetable descriptor for vmem 0xFFFFFFF7FF800000. physaddr = tablebase + (0x6<<12).

Secure Monitor

Unless otherwise mentionned, block descriptors (in our case, the one uses for the DRAM identity mapping) are all ORRed by 0x401 and page descriptors by 0x403.

1.0.0

Vmem Physmem Size Descriptor ORR-value Permissions Description
0x1F0000000 0x50041000 0x1000 0x40000000000324 ARM Interrupt Distributor
0x1F0002000 0x50042000 0x1000 0x40000000000324 Interrupt Controller Physical CPU Interface
0x1F0005000 0x70006000 0x1000 0x40000000000324 UART-A
0x1F0007000 0x60006000 0x1000 0x40000000000324 Clock and Reset
0x1F0009000 0x7000E000 0x1000 0x40000000000304 PMC
0x1F000B000 0x60005000 0x1000 0x40000000000304 TMR
0x1F000D000 0x6000C000 0x1000 0x40000000000304 System Registers
0x1F000F000 0x70012000 0x2000 0x40000000000304 SE
0x1F0012000 0x700F0000 0x1000 0x40000000000304 SYSCTR0
0x1F0014000 0x70019000 0x1000 0x40000000000304 MC
0x1F0016000 0x7000F000 0x1000 0x40000000000304 FUSE
0x1F0018000 0x70000000 0x4000 0x40000000000304 MISC
0x1F001D000 0x60007000 0x1000 0x40000000000304 Flow controller
0x1F001F000 0x40002000 0x1000 0x40000000000304 IRAM
0x1F0021000 0x7000D000 0x1000 0x40000000000304 I2C-5
0x1F0023000 0x6000D000 0x1000 0x40000000000304 GPIO-1
0x1F0025000 0x7000C000 0x1000 0x40000000000304 I2C
0x1F0180000 0x40020000 0x10000 0x40000000000324 IRAM
0x1F01A0000 0x7C010000 0x10000 0x40000000000384 TZRAM
0x1F01C3000 0x80010000 0x10000 0x40000000000324 EMEM
0x1F01C2000 0x8000F000 0x1000 0x40000000000324 EMEM
0x1F01E0000 0x7C013000 0xB000 0x304 TZRAM (Secure Monitor)
0x1F01F0000 0x7C01E000 0x2000 0x304 TZRAM (Secure Monitor and ARMv8 init)
0x1F01F6000 0x7C01E000 0x1000 0x40000000000304 TZRAM
0x1F01F8000 0x7C01F000 0x1000 0x40000000000304 TZRAM
0x1F01FA000 0x7C010000 0x1000 0x304 TZRAM (Secure Monitor exception vectors)
0x1F01FC000 0x7C011000 0x1000 0x40000000000304 TZRAM
0x1F01FE000 0x7C012000 0x1000 0x40000000000304 TZRAM

2.0.0

Vmem Physmem Size Descriptor ORR-value Permissions Description
0x7C010000 0x7C010000 0x10000 0x300 TZRAM
0x40020000 0x40020000 0x20000 0x300 iRAM-C
0x1F0080000 0x50041000 0x1000 0x40000000000304 ARM Interrupt Distributor
0x1F0082000 0x50042000 0x2000 0x40000000000304 Interrupt Controller Physical CPU interface
0x1F0085000 0x70006000 0x1000 0x40000000000324 UART-A
0x1F0087000 0x60006000 0x1000 0x40000000000324 Clock and Reset
0x1F0089000 0x7000E000 0x1000 0x40000000000304 PMC
0x1F008B000 0x60005000 0x1000 0x40000000000304 TMR
0x1F008D000 0x6000C000 0x1000 0x40000000000304 System Registers
0x1F008F000 0x70012000 0x2000 0x40000000000304 SE
0x1F0092000 0x700F0000 0x1000 0x40000000000304 SYSCTR0
0x1F0094000 0x70019000 0x1000 0x40000000000304 MC
0x1F0096000 0x7000F000 0x1000 0x40000000000304 FUSE (0x7000F800)
0x1F0098000 0x70000000 0x4000 0x40000000000304 MISC
0x1F009D000 0x60007000 0x1000 0x40000000000304 Flow Controller
0x1F009F000 0x40002000 0x1000 0x40000000000304 iRAM-A
0x1F00A1000 0x7000D000 0x1000 0x40000000000304 I2C5 - SPI 2B-6
0x1F00A3000 0x6000D000 0x1000 0x40000000000304 GPIO-1 - GPIO-8
0x1F00A5000 0x7000C000 0x1000 0x40000000000304 I2C-I2C4
0x1F00A7000 0x6000F000 0x1000 0x40000000000304 Exception vectors
0x1F0180000 0x40020000 0x10000 0x40000000000324 iRAM-C
0x1F0190000 0x40003000 0x1000 0x40000000000324 iRAM-A
0x1F01A0000 0x7C010000 0x10000 0x40000000000380 TZRAM
0x1F01C3000 0x80010000 0x10000 0x40000000000324 EMEM
0x1F01C2000 0x8000F000 0x1000 0x40000000000324 EMEM
0x1F01E0000 0x7C013000 0xB000 0x300 TZRAM (Secure Monitor)
0x1F01F0000 0x7C01E000 0x2000 0x300 TZRAM (Secure Monitor and ARMv8 init)
0x1F01F4000 <varies> 0x1000 0x40000000000320 DRAM (SPL .bss buffer visible to the Security Engine)
0x1F01F6000 0x7C01E000 0x1000 0x40000000000300 TZRAM
0x1F01F8000 0x7C01F000 0x1000 0x40000000000300 TZRAM
0x1F01FA000 0x7C010000 0x1000 0x300 TZRAM (Secure Monitor exception vectors)
0x1F01FC000 0x7C011000 0x1000 0x40000000000300 TZRAM
0x1F01FE000 0x7C012000 0x1000 0x40000000000300 TZRAM

5.0.0

5.0.0 modified the address map to have separate .text, .rodata, and .rwdata segments, instead of a single RWX segment.

However, the .rodata and .rwdata segments are both (mistakenly?) mapped R-W.

Because the same L3 page is shared for all mappings, this required modifying segment layout significantly to prevent clashes.

Vmem Physmem Size Descriptor ORR-value Description
0x7C010000 0x7C010000 0x10000 0x300 TZRAM Identity RWX (for init)
0x40020000 0x40020000 0x20000 0x300 IRAM Identity RWX (for init)
0x1F0080000 0x50041000 0x1000 0x40000000000304 ARM Interrupt Distributor
0x1F0082000 0x50042000 0x2000 0x40000000000304 Interrupt Controller Physical CPU
0x1F0085000 0x70006000 0x1000 0x40000000000324 UART-A
0x1F0087000 0x60006000 0x1000 0x40000000000324 Clock and Reset
0x1F0089000 0x7000E000 0x1000 0x40000000000304 PMC
0x1F008B000 0x60005000 0x1000 0x40000000000304 Timers
0x1F008D000 0x6000C000 0x1000 0x40000000000304 System Registers
0x1F008F000 0x70012000 0x2000 0x40000000000304 Security Engine
0x1F00AD000 0x70412000 0x2000 0x40000000000304 Erista: Nothing Present, Mariko: Security Engine 2
0x1F0092000 0x700F0000 0x1000 0x40000000000304 SYSCTR0
0x1F0094000 0x70019000 0x1000 0x40000000000304 Memory Controller
0x1F0096000 0x7000F000 0x1000 0x40000000000304 Fuse Registers
0x1F0098000 0x70000000 0x4000 0x40000000000304 MISC Registers
0x1F009D000 0x60007000 0x1000 0x40000000000304 Flow Controller
0x1F009F000 0x40002000 0x1000 0x40000000000304 IRAM
0x1F00A1000 0x7000D000 0x1000 0x40000000000304 I2C-5
0x1F00A3000 0x6000D000 0x1000 0x40000000000304 GPIO-1
0x1F00A5000 0x7000C000 0x1000 0x40000000000304 I2C
0x1F00A7000 0x6000F000 0x1000 0x40000000000304 BPMP Exception Vectors
0x1F00A9000 0x7001C000 0x1000 0x40000000000304 MC0
0x1F00AB000 0x7001D000 0x1000 0x40000000000304 MC1
0x1F0100000 0x7C010000 0x10000 0x40000000000380 TZRAM (R-- for context save)
0x1F0140000 0x7C012000 0x9000 0x300 TZRAM (R-X .text)
0x1F0149000 0x7C01B000 0x1000 0x40000000000300 TZRAM (RW- .rodata)
0x1F014A000 0x7C01C000 0x2000 0x40000000000300 TZRAM (RW- .rwdata)
0x1F01A0000 0x40020000 0x10000 0x40000000000324 IRAM (RW- for context save)
0x1F01B0000 0x40003000 0x1000 0x40000000000324 IRAM (BPMP firmware destination)
0x1F01C7000 0x8000F000 0x1000 0x40000000000324 DRAM (SE Context Save destination)
0x1F01E0000 0x7C010000 0x2000 0x300 TZRAM (RWX pk2ldr for init)
0x1F01F4000 X 0x1000 0x40000000000723 DRAM (SPL .bss buffer visible to the Security Engine)
0x1F01F6000 0x7C010000 0x1000 0x40000000000300 TZRAM (stacks)
0x1F01F8000 0x7C011000 0x1000 0x40000000000300 TZRAM (stacks)
0x1F01FA000 0x7C01D000 0x1000 0x40000000000300 TZRAM (stacks, warmboot crt0)
0x1F01FC000 0x7C01E000 0x1000 0x40000000000300 TZRAM (L2 Page Table)
0x1F01FE000 0x7C01F000 0x1000 0x40000000000300 TZRAM (L3 Page Table)

6.0.0

6.0.0 reduced the .rwdata segment to one page (previously 2).

Vmem Physmem Size Descriptor ORR-value Description
0x7C010000 0x7C010000 0x10000 0x300 TZRAM Identity RWX (for init)
0x40020000 0x40020000 0x20000 0x300 IRAM Identity RWX (for init)
0x1F0080000 0x50041000 0x1000 0x40000000000304 ARM Interrupt Distributor
0x1F0082000 0x50042000 0x2000 0x40000000000304 Interrupt Controller Physical CPU
0x1F0085000 0x70006000 0x1000 0x40000000000324 UART-A
0x1F0087000 0x60006000 0x1000 0x40000000000324 Clock and Reset
0x1F0089000 0x7000E000 0x1000 0x40000000000304 PMC
0x1F008B000 0x60005000 0x1000 0x40000000000304 Timers
0x1F008D000 0x6000C000 0x1000 0x40000000000304 System Registers
0x1F008F000 0x70012000 0x2000 0x40000000000304 Security Engine
0x1F00AD000 0x70412000 0x2000 0x40000000000304 Erista: Nothing Present, Mariko: Security Engine 2
0x1F0092000 0x700F0000 0x1000 0x40000000000304 SYSCTR0
0x1F0094000 0x70019000 0x1000 0x40000000000304 Memory Controller
0x1F0096000 0x7000F000 0x1000 0x40000000000304 Fuse Registers
0x1F0098000 0x70000000 0x4000 0x40000000000304 MISC Registers
0x1F009D000 0x60007000 0x1000 0x40000000000304 Flow Controller
0x1F009F000 0x40002000 0x1000 0x40000000000304 IRAM
0x1F00A1000 0x7000D000 0x1000 0x40000000000304 I2C-5
0x1F00A3000 0x6000D000 0x1000 0x40000000000304 GPIO-1
0x1F00A5000 0x7000C000 0x1000 0x40000000000304 I2C
0x1F00A7000 0x6000F000 0x1000 0x40000000000304 BPMP Exception Vectors
0x1F00A9000 0x7001C000 0x1000 0x40000000000304 MC0
0x1F00AB000 0x7001D000 0x1000 0x40000000000304 MC1
0x1F0100000 0x7C010000 0x10000 0x40000000000380 TZRAM (R-- for context save)
0x1F0140000 0x7C012000 0x9000 0x300 TZRAM (R-X .text)
0x1F0149000 0x7C01B000 0x1000 0x40000000000300 TZRAM (RW- .rodata)
0x1F014A000 0x7C01C000 0x1000 0x40000000000300 TZRAM (RW- .rwdata)
0x1F01A0000 0x40020000 0x10000 0x40000000000324 IRAM (RW- for context save)
0x1F01B0000 0x40003000 0x1000 0x40000000000324 IRAM (BPMP firmware destination)
0x1F01C7000 0x8000F000 0x1000 0x40000000000324 DRAM (SE Context Save destination)
0x1F01E0000 0x7C010000 0x2000 0x300 TZRAM (RWX pk2ldr for init)
0x1F01F4000 X 0x1000 0x40000000000723 DRAM (SPL .bss buffer visible to the Security Engine)
0x1F01F6000 0x7C010000 0x1000 0x40000000000300 TZRAM (stacks)
0x1F01F8000 0x7C011000 0x1000 0x40000000000300 TZRAM (stacks)
0x1F01FA000 0x7C01D000 0x1000 0x40000000000300 TZRAM (stacks, warmboot crt0)
0x1F01FC000 0x7C01E000 0x1000 0x40000000000300 TZRAM (L2 Page Table)
0x1F01FE000 0x7C01F000 0x1000 0x40000000000300 TZRAM (L3 Page Table)

IRAM

BIT

During boot, the BootROM saves the BCT in IRAM at address 0x40000100 with Erista, and 0x40000464 with Mariko. The preceding 0x100 bytes (IRAM memory range from 0x40000000 to 0x40000100) contain a structure called BIT (Boot Info Table) which encapsulates the BCT in IRAM and is initialized by the BootROM as follows:

Erista

Offset Size Field Description
0x00 0x04 BootRomVersion Set to 0x00210001 (BOOTDATA_VERSION_T210).
0x04 0x04 DataVersion Set to 0x00210001 (BOOTDATA_VERSION_T210).
0x08 0x04 RcmVersion Set to 0x00210001 (BOOTDATA_VERSION_T210).
0x0C 0x04 BootType
None = 0
Cold = 1
Recovery = 2
Uart = 3
ExitRcm = 4
0x10 0x04 PrimaryDevice Set to 0x05 (IROM) on coldboot.
0x14 0x04 SecondaryDevice Set to 0x04 (SDMMC) on coldboot.
0x18 0x04*0x04 BootTimeLog
Offset Size Field
0x00 0x04 BootTimeLogInit
0x04 0x04 BootTimeLogExit
0x08 0x04 BootReadBctTickCnt
0x0C 0x04 BootReadBLTickCnt
0x28 0x04 OscFrequency Value from CLK_RST_CONTROLLER_OSC_CTRL.
0x2C 0x01 DevInitialized Set to 1 after the boot device is initialized.
0x2D 0x01 SdramInitialized Set to 1 after the SDRAM parameters are parsed.
0x2E 0x01 ClearedForceRecovery Set to 1 if bit 2 was set in APBDEV_PMC_SCRATCH0.
0x2F 0x01 ClearedFailBack Set to 1 if bit 4 was set in APBDEV_PMC_SCRATCH0.
0x30 0x01 InvokedFailBack Set to 1 if the bootloaders have different versions in the BCT.
0x31 0x01 IRomPatchStatus
0x32 0x01 BctValid Set to 1 if the BCT was parsed successfully.
0x33 0x09 BctStatus Each bit contains the status for BCT reads in a given block.
0x3C 0x04 BctLastJournalRead Contains the status of the last journal block read.
None = 0
Success = 1
ValidationFailure = 2
DeviceReadError = 3
0x40 0x04 BctBlock Block number where the BCT was found.
0x44 0x04 BctPage Page number where the BCT was found.
0x48 0x04 BctSize Size of the BCT in IRAM (0x2800).
0x4C 0x04 BctPtr Pointer to the BCT in IRAM (0x40000100).
0x50 0x18*0x04 BlState Contains the state of attempts to load each bootloader.
Offset Size Field
0x00 0x04 Status
0x04 0x04 FirstEccBlock
0x08 0x04 FirstEccPage
0x0C 0x04 FirstCorrectedEccBlock
0x10 0x04 FirstCorrectedEccPage
0x14 0x01 HadEccError
0x15 0x01 HadCrcError
0x16 0x01 HadCorrectedEccError
0x17 0x01 UsedForEccRecovery
0xB0 0x3C SecondaryDevStatus Structure to hold secondary boot device status.

For SDMMC, the following applies:

Offset Size Field
0x00 0x01 FuseDataWidth
0x01 0x01 FuseVoltageRange
0x02 0x01 FuseDisableBootMode
0x03 0x01 FuseDdrMode
0x04 0x01 DiscoveredCardType
0x05 0x03 Reserved
0x08 0x04 DiscoveredVoltageRange
0x0C 0x01 DataWidthUnderUse
0x0D 0x01 PowerClassUnderUse
0x0E 0x01 AutoCalStatus
0x0F 0x01 Reserved
0x10 0x10 Cid
0x20 0x04 NumPagesRead
0x24 0x04 NumCrcErrors
0x25 0x01 BootFromBootPartition
0x26 0x01 BootModeReadSuccessful
0x27 0x15 Reserved
0xEC 0x04 UsbChargingStatus
0xF0 0x04 SafeStartAddr Pointer to the end of the BCT in IRAM (0x40002900).
0xF4 0x0C Reserved Must be empty.

Mariko

Offset Size Field Description
0x00 0x04 BootRomVersion Set to 0x00210001 (BOOTDATA_VERSION_T210).
0x04 0x04 DataVersion Set to 0x00210001 (BOOTDATA_VERSION_T210).
0x08 0x04 RcmVersion Set to 0x00210001 (BOOTDATA_VERSION_T210).
0x0C 0x04 BootType
None = 0
Cold = 1
Recovery = 2
Uart = 3
ExitRcm = 4
0x10 0x04 PrimaryDevice Set to 0x05 (IROM) on coldboot.
0x14 0x04 SecondaryDevice Set to 0x04 (SDMMC) on coldboot.
0x18 0x04 AuthenticationScheme
0x1C 0x01 EncryptionEnabled
0x1D 0x03 Reserved
0x20 0x04 BootROMtracker
0x24 0x05*0x04 BootTimeLog
Offset Size Field
0x00 0x04 BootTimeLogInit
0x04 0x04 BootTimeLogExit
0x08 0x04 BootSetupTickCnt
0x0C 0x04 BootReadBctTickCnt
0x10 0x04 BootReadBLTickCnt
0x38 0x10*0x28 BootFlowLog
Offset Size Field
0x00 0x04 BootFlowLogInit
0x04 0x04 BootFlowLogExit
0x08 0x04 BootFlowFuncId
0x0C 0x04 BootFlowFuncStatus
0x2B8 0x04 OscFrequency Value from CLK_RST_CONTROLLER_OSC_CTRL.
0x2BC 0x01 DevInitialized Set to 1 after the boot device is initialized.
0x2BD 0x01 SdramInitialized Set to 1 after the SDRAM parameters are parsed.
0x2BE 0x01 ClearedForceRecovery Set to 1 if bit 2 was set in APBDEV_PMC_SCRATCH0.
0x2BF 0x01 ClearedFailBack Set to 1 if bit 4 was set in APBDEV_PMC_SCRATCH0.
0x2C0 0x01 InvokedFailBack Set to 1 if the bootloaders have different versions in the BCT.
0x2C1 0x01 IRomPatchStatus
0x2C2 0x01 BctSizeValid
0x2C3 0x09 BctSizeStatus
0x2CC 0x04 BctSizeLastJournalRead
0x2D0 0x04 BctSizeBlock
0x2D4 0x04 BctSizePage
0x2D8 0x01 BctValid Set to 1 if the BCT was parsed successfully.
0x2D9 0x09 BctStatus Each bit contains the status for BCT reads in a given block.
0x2E2 0x02 Reserved
0x2E4 0x04 BctLastJournalRead Contains the status of the last journal block read.
None = 0
Success = 1
ValidationFailure = 2
DeviceReadError = 3
0x2E8 0x04 BctBlock Block number where the BCT was found.
0x2EC 0x04 BctPage Page number where the BCT was found.
0x2F0 0x04 BctSize Size of the BCT in IRAM.
0x2F4 0x04 BctPtr Pointer to the BCT in IRAM.
0x2F8 0x18*0x04 BlState Contains the state of attempts to load each bootloader.
Offset Size Field
0x00 0x04 Status
0x04 0x04 FirstEccBlock
0x08 0x04 FirstEccPage
0x0C 0x04 FirstCorrectedEccBlock
0x10 0x04 FirstCorrectedEccPage
0x14 0x01 HadEccError
0x15 0x01 HadCrcError
0x16 0x01 HadCorrectedEccError
0x17 0x01 UsedForEccRecovery
0x358 0x100 SecondaryDevStatus Structure to hold secondary boot device status.
0x458 0x03 Reserved
0x45B 0x04 UsbChargingStatus
0x45F 0x01 PmuBootSelReadError
0x460 0x04 SafeStartAddr Pointer to the end of the BCT in IRAM.

Carveouts

The MC (Memory Controller) provides multiple configurable memory carveouts which allow to protect and limit access to sensitive DRAM regions. Carveouts work on the physical access level, thus acting as the last protection barrier from unauthorized memory accesses.

A total of 9 programmable carveouts are available from which 4 have a fixed function (TZDRAM, VPR, SEC and MTS) and 5 are generalized carevouts (GSCs 1 to 5).

TZDRAM Carveout

Defines a DRAM region that can only be accessed by TrustZone-secure clients. Currently unused by the Switch.

This carveout is controlled by the following MC registers:

MC_SECURITY_CFG0
MC_SECURITY_CFG1
MC_SECURITY_CFG3

VPR Carveout

Defines a DRAM region that can only be accessed by clients that are part of the video decode and display process (Display, GPU, TSEC, VIC, NVENC, NVDEC and HDA). Currently unused by the Switch.

This carveout is controlled by the following MC registers:

MC_VIDEO_PROTECT_GPU_OVERRIDE_0
MC_VIDEO_PROTECT_GPU_OVERRIDE_1
MC_VIDEO_PROTECT_BOM
MC_VIDEO_PROTECT_SIZE_MB
MC_VIDEO_PROTECT_REG_CTRL

SEC Carveout

Defines a DRAM region that can only be accessed by the TSEC. Deprecated and unused by the Switch.

This carveout is controlled by the following MC registers:

MC_SEC_CARVEOUT_BOM
MC_SEC_CARVEOUT_SIZE_MB
MC_SEC_CARVEOUT_REG_CTRL

MTS Carveout

Defines a DRAM region for Falcon microcode. Deprecated and unused by the Switch.

This carveout is controlled by the following MC registers:

MC_MTS_CARVEOUT_BOM
MC_MTS_CARVEOUT_SIZE_MB
MC_MTS_CARVEOUT_ADR_HI
MC_MTS_CARVEOUT_REG_CTRL

Generalized Carveouts

These carveouts can be freely configured for any client that supports them.

These carveouts are controlled by the following MC registers:

MC_SECURITY_CARVEOUT1/2/3/4/5_BOM
MC_SECURITY_CARVEOUT1/2/3/4/5_BOM_HI
MC_SECURITY_CARVEOUT1/2/3/4/5_SIZE_128KB
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS0
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS1
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS2
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS3
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_ACCESS4
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS0
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS1
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS2
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS3
MC_SECURITY_CARVEOUT1/2/3/4/5_CLIENT_FORCE_INTERNAL_ACCESS4
MC_SECURITY_CARVEOUT1/2/3/4/5_CFG0

The client access registers (CLIENT_ACCESS0/1/2/3/4) are used to whitelist accesses from MC clients as follows:

Bits ClientAccess0 ClientAccess1 ClientAccess2 ClientAccess3 ClientAccess4
0 CSR_PTCR Reserved CSW_VDEMBEW CSR_SDMMCRA CSR_SESRD
1 CSR_DISPLAY0A Reserved CSW_VDETPMW CSR_SDMMCRAA CSW_SESWR
2 CSR_DISPLAY0AB CSR_VDEBSEVR Reserved CSR_SDMMCR CSR_AXIAPR
3 CSR_DISPLAY0B CSR_VDEMBER Reserved CSR_SDMMCRAB CSW_AXIAPW
4 CSR_DISPLAY0BB CSR_VDEMCER CSR_ISPRA CSW_SDMMCWA CSR_ETRR
5 CSR_DISPLAY0C CSR_VDETPER Reserved CSW_SDMMCWAA CSW_ETRW
6 CSR_DISPLAY0CB CSR_MPCORELPR CSW_ISPWA CSW_SDMMCW CSR_TSECSRDB
7 Reserved CSR_MPCORER CSW_ISPWB CSW_SDMMCWAB CSW_TSECSWRB
8 Reserved Reserved Reserved Reserved CSR_GPUSRD2
9 Reserved Reserved Reserved Reserved CSW_GPUSWR2
10 Reserved Reserved CSR_XUSB_HOSTR Reserved Reserved
11 Reserved CSW_NVENCSWR CSW_XUSB_HOSTW Reserved Reserved
12 Reserved Reserved CSR_XUSB_DEVR CSR_VICSRD Reserved
13 Reserved Reserved CSW_XUSB_DEVW CSW_VICSWR Reserved
14 CSR_AFIR Reserved CSR_ISPRAB (Erista) or CSR_SE2SRD (Mariko) Reserved Reserved
15 CSR_AVPCARM7R Reserved Reserved Reserved Reserved
16 CSR_DISPLAYHC Reserved CSW_ISPWAB (Erista) or CSW_SE2SWR (Mariko) Reserved Reserved
17 CSR_DISPLAYHCB CSW_AFIW CSW_ISPWBB (Erista) or Reserved (Mariko) Reserved Reserved
18 Reserved CSW_AVPCARM7W Reserved CSW_VIW Reserved
19 Reserved Reserved Reserved CSR_DISPLAYD Reserved
20 Reserved Reserved CSR_TSECSRD Reserved Reserved
21 CSR_HDAR CSW_HDAW CSW_TSECSWR Reserved Reserved
22 CSR_HOST1XDMAR CSW_HOST1XW CSR_A9AVPSCR Reserved Reserved
23 CSR_HOST1XR Reserved CSW_A9AVPSCW Reserved Reserved
24 Reserved CSW_MPCORELPW CSR_GPUSRD CSR_NVDECSRD Reserved
25 Reserved CSW_MPCOREW CSW_GPUSWR CSW_NVDECSWR Reserved
26 Reserved Reserved CSR_DISPLAYT CSR_APER Reserved
27 Reserved CSW_PPCSAHBDMAW Reserved CSW_APEW Reserved
28 CSR_NVENCSRD CSW_PPCSAHBSLVW Reserved Reserved Reserved
29 CSR_PPCSAHBDMAR CSW_SATAW Reserved Reserved Reserved
30 CSR_PPCSAHBSLVR CSW_VDEBSEVW Reserved CSR_NVJPGSRD Reserved
31 CSR_SATAR CSW_VDEDBGW Reserved CSW_NVJPGSWR Reserved

The configuration register (CFG0) is used to control the carveout's properties as follows:

Bits Description
0 PROTECT_MODE
0: LOCKBIT_SECURE (registers cannot be modified after lock down)
1: TZ_SECURE (registers can be modified by TZ after lock down)
1 LOCK_MODE
0: UNLOCKED (registers can be modified at any time)
1: LOCKED (registers cannot be modified until reset)
2 ADDRESS_TYPE
0: ANY_ADDRESS
1: UNTRANSLATED_ONLY
3-6 READ_ACCESS_LEVEL
Bit 0: Access level 0 (default for all clients)
Bit 1: Access level 1 (unknown)
Bit 2: Access level 2 (Falcon clients in LS mode)
Bit 3: Access level 3 (Falcon clients in HS mode)
7-10 WRITE_ACCESS_LEVEL
Bit 0: Access level 0 (default for all clients)
Bit 1: Access level 1 (unknown)
Bit 2: Access level 2 (Falcon clients in LS mode)
Bit 3: Access level 3 (Falcon clients in HS mode)
11-13 APERTURE_ID
14-17 DISABLE_READ_CHECK_ACCESS_LEVEL
Bit 0: Disable read access level 0 check
Bit 1: Disable read access level 1 check
Bit 2: Disable read access level 2 check
Bit 3: Disable read access level 3 check
18-21 DISABLE_WRITE_CHECK_ACCESS_LEVEL
Bit 0: Disable write access level 0 check
Bit 1: Disable write access level 1 check
Bit 2: Disable write access level 2 check
Bit 3: Disable write access level 3 check
22 SEND_CFG_TO_GPU
0: DISABLED
1: ENABLED
23 TZ_GLOBAL_WR_EN
0: DISABLED
1: BYPASS_CHECK
24 TZ_GLOBAL_RD_EN
0: DISABLED
1: BYPASS_CHECK
25 ALLOW_APERTURE_ID_MISMATCH
0: DISABLED
1: ENABLED
26 FORCE_APERTURE_ID_MATCH
0: DISABLED
1: ENABLED
27 IS_WPR
0: DISABLED
1: ENABLED

GSC1

This carveout is, by default, for NVDEC. In the Switch's case, this carveout is not used.

It is configured as follows:

*(u32 *)MC_SECURITY_CARVEOUT1_BOM = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_BOM_HI = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_SIZE_128KB = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
*(u32 *)MC_SECURITY_CARVEOUT1_CFG0 = 0x4000006;

GSC2

This carveout is, by default and in the Switch's case, for the GPU (WPR1).

It is configured as follows:

*(u32 *)MC_SECURITY_CARVEOUT2_BOM = 0x80020000;
*(u32 *)MC_SECURITY_CARVEOUT2_BOM_HI = 0;
*(u32 *)MC_SECURITY_CARVEOUT2_SIZE_128KB = 2;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2 = 0x3000000;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4 = 0x300;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
*(u32 *)MC_SECURITY_CARVEOUT2_CFG0 = 0x440167E;

GSC3

This carveout is, by default, for the GPU (WPR2). In the Switch's case, this carveout is not used.

It is configured as follows:

*(u32 *)MC_SECURITY_CARVEOUT3_BOM = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_BOM_HI = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_SIZE_128KB = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2 = 0x3000000;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4 = 0x300;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
*(u32 *)MC_SECURITY_CARVEOUT3_CFG0 = 0x4401E7E;

GSC4

This carveout is, by default, for TSECA. In the Switch's case, this carveout is used by the Kernel.

It is initially configured as follows:

*(u32 *)MC_SECURITY_CARVEOUT4_BOM = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_BOM_HI = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_SIZE_128KB = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
*(u32 *)MC_SECURITY_CARVEOUT4_CFG0 = 0x8F;

Then further configured using smcConfigureCarveout.

GSC5

This carveout is, by default, for TSECB. In the Switch's case, this carveout is used by the Kernel.

It is initially configured as follows:

*(u32 *)MC_SECURITY_CARVEOUT5_BOM = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_BOM_HI = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_SIZE_128KB = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4 = 0;
*(u32 *)MC_SECURITY_CARVEOUT5_CFG0 = 0x8F;

Then further configured using smcConfigureCarveout.