github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/arm/mmu.go (about) 1 // ARM processor support 2 // https://github.com/usbarmory/tamago 3 // 4 // Copyright (c) WithSecure Corporation 5 // https://foundry.withsecure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 package arm 11 12 import ( 13 "runtime" 14 15 "github.com/usbarmory/tamago/internal/reg" 16 ) 17 18 const ( 19 l1pageTableOffset = 0x4000 20 l1pageTableSize = 4096 21 22 l2pageTableOffset = 0xc000 23 l2pageTableSize = 256 24 ) 25 26 // Memory region attributes 27 // (Table B3-10, ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition). 28 const ( 29 TTE_PAGE_TABLE uint32 = (1 << 0) 30 TTE_SECTION uint32 = (1 << 1) 31 TTE_BUFFERABLE uint32 = (1 << 2) 32 TTE_CACHEABLE uint32 = (1 << 3) 33 TTE_EXECUTE_NEVER uint32 = (1 << 4) 34 TTE_SUPERSECTION uint32 = (1 << 18) | (1 << 1) 35 TTE_NS uint32 = (1 << 19) 36 ) 37 38 // MMU access permissions 39 // (Table B3-8, ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition). 40 const ( 41 // PL1: no access PL0: no access 42 TTE_AP_000 uint32 = 0b00 43 // PL1: read/write PL0: no access 44 TTE_AP_001 uint32 = 0b01 45 // PL1: read/write PL0: read only 46 TTE_AP_010 uint32 = 0b10 47 // PL1: read/write PL0: read/write 48 TTE_AP_011 uint32 = 0b11 49 ) 50 51 const ( 52 MemoryRegion = TTE_AP_001<<10 | TTE_CACHEABLE | TTE_BUFFERABLE | TTE_SECTION 53 DeviceRegion = TTE_AP_001<<10 | TTE_SECTION 54 ) 55 56 // defined in mmu.s 57 func flush_tlb() 58 func set_ttbr0(addr uint32) 59 60 // First level address translation 61 // 9.4, ARM® Cortex™ -A Series Programmer’s Guide 62 func (cpu *CPU) initL1Table(entry int, ttbr uint32, section uint32) { 63 ramStart, ramEnd := runtime.MemRegion() 64 _, textEnd := runtime.TextRegion() 65 66 for i := uint32(entry); i < l1pageTableSize; i++ { 67 page := ttbr + 4*i 68 addr := section + (i << 20) 69 70 switch { 71 case addr < textEnd && (addr+(1<<20)) > textEnd: 72 // skip first L2 table, reserved to trap null pointers 73 l2pageTableStart := cpu.vbar + l2pageTableOffset 74 base := l2pageTableStart + l2pageTableSize*4 75 76 // use L2 table to end non-executable boundary 77 // precisely at textStart 78 reg.Write(page, base|TTE_PAGE_TABLE) 79 cpu.initL2Table(0, base, addr) 80 case addr >= ramStart && addr < textEnd: 81 reg.Write(page, addr|MemoryRegion) 82 case addr >= ramStart && addr < ramEnd: 83 reg.Write(page, addr|MemoryRegion|TTE_EXECUTE_NEVER) 84 default: 85 reg.Write(page, addr|DeviceRegion|TTE_EXECUTE_NEVER) 86 } 87 } 88 } 89 90 // Level 2 translation tables 91 // 9.5, ARM® Cortex™ -A Series Programmer’s Guide 92 func (cpu *CPU) initL2Table(entry int, base uint32, section uint32) { 93 ramStart, ramEnd := runtime.MemRegion() 94 _, textEnd := runtime.TextRegion() 95 96 memoryRegion := TTE_AP_001<<4 | TTE_CACHEABLE | TTE_BUFFERABLE | TTE_SECTION 97 deviceRegion := TTE_AP_001<<4 | TTE_SECTION 98 99 for i := uint32(entry); i < l2pageTableSize; i++ { 100 page := base + 4*i 101 addr := section + (i << 12) 102 103 switch { 104 case addr >= ramStart && addr < textEnd: 105 reg.Write(page, addr|memoryRegion) 106 case addr >= ramStart && addr < ramEnd: 107 reg.Write(page, addr|memoryRegion|TTE_EXECUTE_NEVER) 108 default: 109 reg.Write(page, addr|deviceRegion|TTE_EXECUTE_NEVER) 110 } 111 } 112 } 113 114 // InitMMU initializes the first-level translation tables for all available 115 // memory with a flat mapping and privileged attribute flags. 116 // 117 // The first 4096 bytes (0x00000000 - 0x00001000) are flagged as invalid to 118 // trap null pointers, applications that need to make use of this memory space 119 // must use ConfigureMMU to reconfigure as required. 120 // 121 // All available memory is marked as non-executable except for the range 122 // returned by runtime.TextRegion(). 123 func (cpu *CPU) InitMMU() { 124 l1pageTableStart := cpu.vbar + l1pageTableOffset 125 l2pageTableStart := cpu.vbar + l2pageTableOffset 126 127 // Map the first L1 entry to an L2 table to trap null pointers within 128 // the smallest possible section (4KB starting from 0x00000000). 129 firstSection := l2pageTableStart | TTE_PAGE_TABLE 130 reg.Write(l1pageTableStart, firstSection) 131 132 // set first L2 entry as invalid 133 reg.Write(l2pageTableStart, 0) 134 135 // set remaining entries with flat mapping 136 cpu.initL1Table(1, l1pageTableStart, 0) 137 cpu.initL2Table(1, l2pageTableStart, 0) 138 139 set_ttbr0(l1pageTableStart) 140 } 141 142 // ConfigureMMU (re)configures the first-level translation tables for the 143 // provided memory range with the argument attribute flags. An alias argument 144 // greater than zero specifies the physical address corresponding to the start 145 // argument in case virtual memory is required, otherwise a flat 1:1 mapping is 146 // set. 147 func (cpu *CPU) ConfigureMMU(start, end, alias, flags uint32) { 148 l1pageTableStart := cpu.vbar + l1pageTableOffset 149 150 start = start >> 20 151 end = end >> 20 152 alias = alias >> 20 153 154 var pa uint32 155 156 for i := start; i < l1pageTableSize; i++ { 157 if i >= end { 158 break 159 } 160 161 page := l1pageTableStart + 4*i 162 163 if alias > 0 { 164 pa = (alias + i - start) << 20 165 } else { 166 pa = i << 20 167 } 168 169 reg.Write(page, pa|flags) 170 } 171 172 cpu.FlushDataCache() 173 cpu.FlushTLBs() 174 } 175 176 func (cpu *CPU) updateMMU(start uint32, end uint32, pos int, mask int, val uint32) { 177 l1pageTableStart := cpu.vbar + l1pageTableOffset 178 179 start = start >> 20 180 end = end >> 20 181 182 for i := start; i < l1pageTableSize; i++ { 183 if i >= end { 184 break 185 } 186 187 page := l1pageTableStart + 4*i 188 reg.SetN(page, pos, mask, val) 189 } 190 191 cpu.FlushDataCache() 192 cpu.FlushTLBs() 193 } 194 195 // SetAccessPermissions (re)configures the first-level translation tables for 196 // the provided memory range with the argument domain and access permissions. 197 func (cpu *CPU) SetAccessPermissions(start, end, ap, domain uint32) { 198 cpu.updateMMU(start, end, 5, 0b1101111, (ap<<5)|(domain&0xf)) 199 } 200 201 // SetFlags (re)configures the first-level translation tables for the provided 202 // memory range with the argument attribute flags. 203 func (cpu *CPU) SetAttributes(start, end, flags uint32) { 204 mask := TTE_NS | TTE_SUPERSECTION | TTE_EXECUTE_NEVER | TTE_CACHEABLE | 205 TTE_BUFFERABLE | TTE_SECTION | TTE_PAGE_TABLE 206 207 cpu.updateMMU(start, end, 0, int(mask), flags) 208 }