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");
}
|