github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/arm/mmu.go (about)

     1  // ARM processor support
     2  // https://github.com/f-secure-foundry/tamago
     3  //
     4  // Copyright (c) F-Secure Corporation
     5  // https://foundry.f-secure.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/f-secure-foundry/tamago/internal/reg"
    16  )
    17  
    18  const (
    19  	l1pageTableOffset = 0x4000
    20  	l1pageTableSize   = 0x4000
    21  	l2pageTableOffset = 0xc000
    22  	l2pageTableSize   = 0x4000
    23  )
    24  
    25  // Memory region attributes
    26  // (Table B3-10, ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition).
    27  const (
    28  	TTE_PAGE_TABLE    uint32 = (1 << 0)
    29  	TTE_SECTION       uint32 = (1 << 1)
    30  	TTE_BUFFERABLE    uint32 = (1 << 2)
    31  	TTE_CACHEABLE     uint32 = (1 << 3)
    32  	TTE_EXECUTE_NEVER uint32 = (1 << 4)
    33  	TTE_SUPERSECTION  uint32 = (1 << 18) | (1 << 1)
    34  	TTE_NS            uint32 = (1 << 19)
    35  )
    36  
    37  // MMU access permissions
    38  // (Table B3-8, ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition).
    39  const (
    40  	// PL1: no access   PL0: no access
    41  	TTE_AP_000 uint32 = 0b000
    42  	// PL1: read/write  PL0: no access
    43  	TTE_AP_001 uint32 = 0b001
    44  	// PL1: read/write  PL0: read only
    45  	TTE_AP_010 uint32 = 0b010
    46  	// PL1: read/write  PL0: read/write
    47  	TTE_AP_011 uint32 = 0b011
    48  	// Reserved
    49  	TTE_AP_100 uint32 = 0b100
    50  	// PL1: read only   PL0: no access
    51  	TTE_AP_101 uint32 = 0b101
    52  	// PL1: read only   PL0: read only
    53  	TTE_AP_110 uint32 = 0b110
    54  	// PL1: read only   PL0: read only
    55  	TTE_AP_111 uint32 = 0b111
    56  )
    57  
    58  // defined in mmu.s
    59  func set_ttbr0(addr uint32)
    60  
    61  // ConfigureMMU (re)configures the first-level translation tables for the
    62  // provided memory range with the passed attribute flags.
    63  func (cpu *CPU) ConfigureMMU(start uint32, end uint32, flags uint32) {
    64  	ramStart, _ := runtime.MemRegion()
    65  	l1pageTableStart := ramStart + l1pageTableOffset
    66  
    67  	start = start >> 20
    68  	end = end >> 20
    69  
    70  	for i := uint32(0); i < l1pageTableSize/4; i++ {
    71  		page := l1pageTableStart + 4*i
    72  		pa := i << 20
    73  
    74  		if i < start {
    75  			continue
    76  		}
    77  
    78  		if i >= end {
    79  			break
    80  		}
    81  
    82  		reg.Write(page, pa|flags)
    83  	}
    84  
    85  	cpu.FlushDataCache()
    86  	set_ttbr0(l1pageTableStart)
    87  }
    88  
    89  // InitMMU initializes the first-level translation tables for all available
    90  // memory with a flat mapping and privileged attribute flags.
    91  //
    92  // The first 4096 bytes (0x00000000 - 0x00001000) are flagged as invalid to
    93  // trap null pointers, applications that need to make use of this memory space
    94  // must use ConfigureMMU to reconfigure as required.
    95  func (cpu *CPU) InitMMU() {
    96  	start, end := runtime.MemRegion()
    97  
    98  	l1pageTableStart := start + l1pageTableOffset
    99  	l2pageTableStart := start + l2pageTableOffset
   100  
   101  	// First level address translation
   102  	// 9.4, ARM® Cortex™ -A Series Programmer’s Guide
   103  
   104  	memAttr := (TTE_AP_001&0b11)<<10 | TTE_CACHEABLE | TTE_BUFFERABLE | TTE_SECTION
   105  	devAttr := (TTE_AP_001&0b11)<<10 | TTE_SECTION
   106  
   107  	// The first section is mapped with an L2 entry as we need to map the
   108  	// smallest possible section starting from 0x0 as invalid to trap null
   109  	// pointers.
   110  	firstSection := l2pageTableStart | TTE_PAGE_TABLE
   111  	reg.Write(l1pageTableStart, firstSection)
   112  
   113  	for i := uint32(1); i < l1pageTableSize/4; i++ {
   114  		page := l1pageTableStart + 4*i
   115  		pa := i << 20
   116  
   117  		if pa >= start && pa < end {
   118  			reg.Write(page, pa|memAttr)
   119  		} else {
   120  			reg.Write(page, pa|devAttr)
   121  		}
   122  	}
   123  
   124  	// Level 2 translation tables
   125  	// 9.5, ARM® Cortex™ -A Series Programmer’s Guide
   126  
   127  	memAttr = (TTE_AP_001&0b11)<<4 | TTE_CACHEABLE | TTE_BUFFERABLE | TTE_SECTION
   128  	devAttr = (TTE_AP_001&0b11)<<4 | TTE_SECTION
   129  
   130  	// trap nil pointers by setting the first 4KB section as invalid
   131  	reg.Write(l2pageTableStart, 0)
   132  
   133  	for i := uint32(1); i < 256; i++ {
   134  		page := l2pageTableStart + 4*i
   135  		pa := i << 12
   136  
   137  		if pa >= start && pa < end {
   138  			reg.Write(page, pa|memAttr)
   139  		} else {
   140  			reg.Write(page, pa|devAttr)
   141  		}
   142  	}
   143  
   144  	set_ttbr0(l1pageTableStart)
   145  }