aboutsummaryrefslogtreecommitdiff
path: root/paging.c
blob: 7c2a9de55f734741c9dd94242bc30913c3f1804b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include "cp_regs.h"
#include "uart.h"
#include "strings.h"
#include "memory.h"
#include "translation_table_descriptors.h"

void setup_flat_map(void)
{
  char bits[33]; // for printing uint32_t bit values
  
  // compute translation table base address
  // translation table shall start at first 2^14-bytes aligned
  // address after the kernel image

  uint32_to_bits(TRANSLATION_TABLE_BASE, bits);
  uart_puts("binary representation of chosen"
	    " lvl1 translation table address: ");
  uart_puts(bits); uart_puts("\n\r");
 
  // flat map all memory
  uart_puts("preparing translation table\n\r");
  short_descriptor_lvl1_t volatile *translation_table =
    (short_descriptor_lvl1_t*) TRANSLATION_TABLE_BASE;
  
  for (uint32_t i = 0; i < 4096; i++)
      translation_table[i].section_fields =
	(short_section_descriptor_t) {
	.SECTION_BASE_ADDRESS_31_20  = i,
	.SECTION_OR_SUPERSECTION_BIT = DESCRIBES_SECTION,
	.ACCESS_PERMISSIONS_2        = AP_2_0_MODEL_RW_PL1 >> 2,
	.ACCESS_PERMISSIONS_1_0      = AP_2_0_MODEL_RW_PL1 & 0b011,
	.DESCRIPTOR_TYPE_1           =
	   SHORT_DESCRIPTOR_SECTION_OR_SUPERSECTION >> 1,
	// rest of fields are 0s
      };

  // meddle with domain settings
  uart_puts("setting domain0 to client access"
	    " and blocking other domains\n\r");

  DACR_t DACR = 0;
  DACR = set_domain_permissions(DACR, 0, DOMAIN_CLIENT_ACCESS);
  for (int i = 1; i < 16; i++)
    DACR = set_domain_permissions(DACR, i, DOMAIN_NO_ACCESS);

  // the above should do the same as this:
  // DACR = 1;
  
  asm("mcr p15, 0, %0, c3, c0, 0" :: "r" (DACR));

  // meddle with SCTLR, which determines how some bits in
  // table descriptors work and also controls caches
  // we don't want to use access flag, so we set AFE to 0
  // we don't want TEX remap, so we set TRE to 0
  // we also disable data and instruction caches and the MMU
  
  // some of this is redundant (i.e. MMU should already be disabled)
  uart_puts("setting C, I, AFE and TRE to 0 in SCTLR\n\r");

  SCTLR_t SCTLR;
  asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR.raw));

  SCTLR.fields.M   = 0; // disable MMU
  SCTLR.fields.C   = 0; // disable data cache
  SCTLR.fields.I   = 0; // disable instruction cache
  SCTLR.fields.TRE = 0; // disable TEX remap
  SCTLR.fields.AFE = 0; // disable access flag usage
  asm("mcr p15, 0, %0, c1, c0, 0\n\r"
      "isb" :: "r" (SCTLR.raw) : "memory");

  // TODO: move invalidation instructions to some header as inlines
  
  uart_puts("invalidating instruction cache, branch prediction,"
	    " and entire main TLB\n\r");
  
  // invalidate instruction cache
  asm("mcr p15, 0, r0, c7, c5, 0\n\r" // r0 gets ignored
      "isb" ::: "memory");

  // invalidate branch-prediction
  asm("mcr p15, 0, r0, c7, c5, 6\n\r" // r0 - same as above
      "isb" ::: "memory");

  // invalidate main Translation Lookup Buffer
  asm("mcr p15, 0, %0, c8, c7, 0\n\r"
      "isb" :: "r" (0) : "memory");

  // now set TTBCR to use TTBR0 exclusively
  uart_puts("Setting TTBCR.N to 0, so that"
	    " TTBR0 is used everywhere\n\r");
  
  uint32_t TTBCR = 0;
  asm("mcr p15, 0, %0, c2, c0, 2" :: "r" (TTBCR));
  
  // Now do stuff with TTBR0
  TTBR_t TTBR0;
  TTBR0.raw = 0;
  TTBR0.fields.TTBR_TRANSLATION_TABLE_BASE_ADDRESS =
    TRANSLATION_TABLE_BASE >> 14;
  // rest of TTBR0 remains 0s
  
  asm("mcr p15, 0, %0, c2, c0, 0" :: "r" (TTBR0.raw));

  // enable MMU
  uart_puts("enabling the MMU\n\r");

  // redundant - we already have SCTLR contents in the variable
  // asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR.raw));

  SCTLR.fields.M = 1;

  asm("mcr p15, 0, %0, c1, c0, 0\n\r"
      "isb" :: "r" (SCTLR.raw) : "memory");
}