Skip to content

Commit 4630c5f

Browse files
committed
added MMU utils, removed source includes
1 parent 7a820de commit 4630c5f

File tree

8 files changed

+460
-127
lines changed

8 files changed

+460
-127
lines changed

platform/generic/mmu_utils.c

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#include "lolevel.h"
2+
#include "mmu_utils.h"
3+
4+
#define SECTION_SIZE (0x100000)
5+
#define L2_LARGEPAGE_MEMTYPE_MASK (0x700c)
6+
7+
// load next word to PC, word aligned
8+
#define LDRW_PC_PC_T2 0xf000f8df
9+
10+
unsigned get_l2_largepage_flags_from_l1_section(unsigned addr,
11+
unsigned l1tableaddr) {
12+
// alignment check
13+
if (l1tableaddr & 0x3fff) {
14+
return 0xffffffff;
15+
}
16+
// sanitize address
17+
addr &= 0xfff00000;
18+
unsigned l1at = l1tableaddr;
19+
if (addr < 0x2000000) {
20+
return 0xffffffff;
21+
//l1at = l1tableaddr + 0x4000 + 0x400 + 0x400 + coreid * 0x80;
22+
}
23+
unsigned sat = (addr >> 20) << 2;
24+
unsigned *entry = (unsigned*) (l1at + sat);
25+
unsigned val = *entry;
26+
// must be section or supersection
27+
if ((val & 3) != 2) {
28+
return 0xffffffff;
29+
}
30+
unsigned retval = 0;
31+
retval |= (val & 0x38000) >> 6; // nG, S, APX bits
32+
retval |= (val & 0x7000); // TEX bits (mem type, cacheability)
33+
retval |= (val & 0x10) << 11; // XN bit
34+
retval |= (val & 0xc); // C, B bits (mem type, cacheability)
35+
retval |= (val & 0xc00) >> 6; // AP bits
36+
return retval;
37+
}
38+
39+
int split_l1_supersection(unsigned addr, unsigned l1tableaddr) {
40+
// alignment check
41+
if (l1tableaddr & 0x3fff) {
42+
return -1;
43+
}
44+
// sanitize address
45+
addr &= 0xff000000;
46+
unsigned l1at = l1tableaddr;
47+
if (addr < 0x2000000) {
48+
return -3;
49+
//l1at = l1tableaddr + 0x4000 + 0x400 + 0x400 + coreid * 0x80;
50+
}
51+
unsigned modat = (addr >> 24) << 6;
52+
unsigned n, m = 0;
53+
for (n = 0; n < 16; n++) {
54+
unsigned *entry = (unsigned*) (l1at + modat + n * 4);
55+
unsigned val = *entry;
56+
// leave when not supersection
57+
if ((val & 0x40003) != 0x40002) {
58+
return -2;
59+
}
60+
*entry = (val & 0xfffbffff) | m;
61+
m += SECTION_SIZE;
62+
}
63+
return 0;
64+
}
65+
66+
int assign_l2_table_to_l1_section(unsigned addr, unsigned l1tableaddr,
67+
unsigned l2tableaddr) {
68+
// alignment check
69+
if (l1tableaddr & 0x3fff || l2tableaddr & 0x3ff) {
70+
return -1;
71+
}
72+
// sanitize address
73+
addr &= 0xfff00000;
74+
unsigned l1at = l1tableaddr;
75+
if (addr < 0x2000000) {
76+
return -1;
77+
//l1at = l1tableaddr + 0x4000 + 0x400 + 0x400 + coreid * 0x80;
78+
}
79+
unsigned modat = (addr >> 20) << 2;
80+
unsigned *entry = (unsigned*) (l1at + modat);
81+
unsigned val = *entry;
82+
// must be section or L2 reference, not supersection
83+
if ((val & 0x40003) == 0x40002) {
84+
return -2;
85+
}
86+
*entry = l2tableaddr | 1;
87+
return 0;
88+
}
89+
90+
int create_l2_table(unsigned addr, unsigned l2tableaddr, unsigned flags) {
91+
// alignment check
92+
if (l2tableaddr & 0x3ff) {
93+
return -1;
94+
}
95+
// sanitize address
96+
addr &= 0xfff00000;
97+
// set 'large page' flag
98+
flags = (flags & 0xfffffffc) | 1;
99+
unsigned m, n;
100+
for (n = 0; n < SECTION_SIZE; n += PAGE_SIZE) {
101+
for (m = 0; m < 16; m++) {
102+
unsigned *entry = (unsigned*) (l2tableaddr + m * 4);
103+
*entry = (addr + n) | flags;
104+
}
105+
l2tableaddr += 0x40;
106+
}
107+
return 0;
108+
}
109+
110+
int replace_large_page_in_l2_table(unsigned addr, unsigned replacement,
111+
unsigned l2tableaddr, unsigned flags) {
112+
// alignment check
113+
if (l2tableaddr & 0x3ff || addr & 0xffff || replacement & 0xffff) {
114+
return -1;
115+
}
116+
// set 'large page' flag
117+
flags = (flags & 0xfffffffc) | 1;
118+
addr = (addr >> 16) & 0xf;
119+
l2tableaddr += addr * 0x40;
120+
unsigned m;
121+
for (m = 0; m < 16; m++) {
122+
unsigned *entry = (unsigned*) (l2tableaddr + m * 4);
123+
*entry = replacement | flags;
124+
}
125+
return 0;
126+
}
127+
128+
void replace_rom_page(unsigned romaddr, unsigned ramaddr, unsigned l2addr,
129+
unsigned flags) {
130+
// copy 64kB "large" page to RAM
131+
_memcpy((void*) ramaddr, (void*) romaddr, PAGE_SIZE);
132+
// make L2 table entry point to copied ROM content
133+
replace_large_page_in_l2_table(romaddr, ramaddr, l2addr, flags);
134+
}
135+
136+
void replace_section_with_l2_tbl(unsigned romaddr, unsigned l1addr,
137+
unsigned l2addr, unsigned flags) {
138+
// make a L2 table
139+
create_l2_table(romaddr, l2addr, flags);
140+
// assign the new L2 table to the desired section of ROM (covers 1MB)
141+
assign_l2_table_to_l1_section(romaddr, l1addr, l2addr);
142+
}
143+
144+
void place_fw_hook_t2_64b(unsigned orig, void *new, unsigned origram) {
145+
unsigned *newa = (unsigned*) ((unsigned) new & 0xfffffffc);
146+
*newa = *(unsigned*) orig;
147+
*(newa + 1) = *(unsigned*) (orig + 4);
148+
*(newa + 2) = LDRW_PC_PC_T2;
149+
*(newa + 3) = (orig + 8) | 1;
150+
*(unsigned*) (origram) = LDRW_PC_PC_T2;
151+
*(unsigned*) (origram + 4) = ((unsigned) new + 16) | 1;
152+
}
153+
154+
void place_fw_patch_t2_64b(void *new, unsigned origram) {
155+
*(unsigned*) (origram) = LDRW_PC_PC_T2;
156+
*(unsigned*) (origram + 4) = ((unsigned) new) | 1;
157+
}
158+

platform/generic/mmu_utils.h

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/**
2+
* Cortex A9
3+
*
4+
* Smallest possible L1 chunk is 1MB (a supersection is 16MB).
5+
* A L2 table is for splitting a 1MB chunk into 64kB or even 4kB chunks.
6+
* The fewer/larger chunks the better performance.
7+
*
8+
* The below translation table manipulation functions assume the Canon FW table arrangement:
9+
* - 0x4000 bytes of L1 table for both cores, describing addresses from 32MB upwards
10+
* - 0x400 bytes of L2 table describing address range 0...1024kB, core0
11+
* - 0x400 bytes of L2 table describing address range 0...1024kB, core1
12+
* - 0x80 bytes of L1 table describing address range 0...32MB, core0
13+
* - 0x80 bytes of L1 table describing address range 0...32MB, core1
14+
*
15+
* @note manipulation of the first 32MB is not supported (those are core-specific and RAM anyway).
16+
*/
17+
18+
#ifndef MMU_UTILS_H
19+
#define MMU_UTILS_H
20+
21+
#define PAGE_SIZE (0x10000)
22+
23+
#define B_INSTR_ARM(pc,dest) \
24+
( 0xEA000000 \
25+
| ((( ((unsigned)dest) - ((unsigned)pc) - 8 ) >> 2) & 0x00FFFFFF) \
26+
)
27+
28+
// thumb-2 32-bit bl instruction (verification pending)
29+
#define BL_INSTR_T1(addr, target) \
30+
( 0xd000f000 \
31+
| (( (((unsigned)target-(unsigned)addr-4)>>1) & 0x7ff) << 16) \
32+
| ( (((unsigned)target-(unsigned)addr-4)>>12) & 0x3ff) \
33+
| ( (((unsigned)target-(unsigned)addr-4)&0x80000000)?0x400:0) \
34+
| (( (((unsigned)target-(unsigned)addr-4)&0x80000000) == \
35+
((((unsigned)target-(unsigned)addr-4)&0x400000)<<9))?0x8000000:0) \
36+
| (( (((unsigned)target-(unsigned)addr-4)&0x80000000) == \
37+
((((unsigned)target-(unsigned)addr-4)&0x800000)<<8))?0x20000000:0) \
38+
)
39+
40+
// thumb-2 16-bit branch instruction, t2 encoding
41+
#define B_INSTR_T2(addr, target) \
42+
( 0xe000 \
43+
| ( (((unsigned)target - (unsigned)addr - 4) >> 1) & 0x7ff ) \
44+
)
45+
46+
// thumb-2 32-bit branch instruction (verification pending)
47+
#define B_INSTR_T4(addr, target) \
48+
( 0x9000f000 \
49+
| (( (((unsigned)target-(unsigned)addr-4)>>1) & 0x7ff) << 16) \
50+
| ( (((unsigned)target-(unsigned)addr-4)>>12) & 0x3ff) \
51+
| ( (((unsigned)target-(unsigned)addr-4)&0x80000000)?0x400:0) \
52+
| (( (((unsigned)target-(unsigned)addr-4)&0x80000000) == \
53+
((((unsigned)target-(unsigned)addr-4)&0x400000)<<9))?0x8000000:0) \
54+
| (( (((unsigned)target-(unsigned)addr-4)&0x80000000) == \
55+
((((unsigned)target-(unsigned)addr-4)&0x800000)<<8))?0x20000000:0) \
56+
)
57+
58+
/**
59+
* Retrieves L1 translation table flags in L2 table large page entry format.
60+
*
61+
* @param addr address of source virtual memory chunk (section or supersection in L1 table)
62+
* @param l1tableaddr physical address of Canon-style L1 table (the 16kB aligned main L1 table at its start, to be exact)
63+
* @return 0xffffffff in case of inappropriate table address or unexpected L1 table content, otherwise the flags are returned
64+
*/
65+
unsigned get_l2_largepage_flags_from_l1_section(unsigned addr,
66+
unsigned l1tableaddr);
67+
68+
/**
69+
* Split a 16MB supersection into 16 sections (in place), so that L2 tables can be assigned to them.
70+
*
71+
* @param addr address of 16MB chunk of virtual memory
72+
* @param l1tableaddr physical address of Canon-style L1 table (the 0x4000-byte-aligned main L1 table at its start, to be exact)
73+
* @return nonzero in case of inappropriate table address or missing supersection
74+
*/
75+
int split_l1_supersection(unsigned addr, unsigned l1tableaddr);
76+
77+
/**
78+
* Assign a L2 table to a 1MB section of virtual address range, usually requires previous use of <code>split_l1_supersection</code>.
79+
*
80+
* @apram addr address of virtual memory chunk (16MB, aligned to 16MB)
81+
* @param l1tableaddr physical address of Canon-style L1 table (the 16kB aligned main L1 table at its start, to be exact)
82+
* @param l2tableaddr physical address of L2 table (1024 bytes, 1024-byte alignment)
83+
* @return nonzero in case of inappropriate table address or unexpected L1 table content
84+
*/
85+
int assign_l2_table_to_l1_section(unsigned addr, unsigned l1tableaddr,
86+
unsigned l2tableaddr);
87+
88+
/**
89+
* Create L2 table for 1MB memory at addr, with large pages (64kB).
90+
*
91+
* @param addr address of virtual memory chunk (1MB, aligned to 1MB)
92+
* @param l2tableaddr physical address of L2 table (1024 bytes, 1024-byte alignment)
93+
* @param flags flags in the new page table entries (should probably match those in respective part of L1 table)
94+
* @return nonzero in case of inappropriate table address
95+
*/
96+
int create_l2_table(unsigned addr, unsigned l2tableaddr, unsigned flags);
97+
98+
/**
99+
* Patch one large (64kB) page in L2 table to point to a different part of physical memory.
100+
*
101+
* @param addr offset of virtual memory chunk (64kB, aligned to 64kB) inside the 1MB range of L2 table
102+
* @param replacement address of physical memory chunk (64kB, aligned to 64kB)
103+
* @param l2tableaddr physical address of L2 table (1024 bytes, 1024-byte alignment)
104+
* @param flags flags in the new page table entries (should probably match those in respective part of L1 table)
105+
* @return nonzero in case of inappropriate addresses
106+
*/
107+
int replace_large_page_in_l2_table(unsigned addr, unsigned replacement,
108+
unsigned l2tableaddr, unsigned flags);
109+
110+
/**
111+
* Replace a 64kB large ROM page with its RAM copy.
112+
*
113+
* @param romaddr start of ROM page (64kB aligned), has to fall within the range of L2 table
114+
* @param ramaddr suitable 64kB aligned RAM address
115+
* @param l2addr existing L2 table's address
116+
* @param flags L2 table entry flags
117+
*/
118+
void replace_rom_page(unsigned romaddr, unsigned ramaddr, unsigned l2addr,
119+
unsigned flags);
120+
121+
/**
122+
* Replace L1 section with newly created L2 table.
123+
*
124+
* @param romaddr start of ROM section (1024kB aligned)
125+
* @param l1addr address of Canon-style MMU tables
126+
* @param l2addr L2 table to be placed at this address (0x400-byte alignment)
127+
* @param flags L2 table entry flags
128+
*/
129+
void replace_section_with_l2_tbl(unsigned romaddr, unsigned l1addr,
130+
unsigned l2addr, unsigned flags);
131+
132+
/**
133+
* Function to place a hook, requires 32-bit alignment, assumes thumb2 code.
134+
* The hook function needs 4 words space at its start after which the hook code must be placed.
135+
* When the hook is finished, jumping to start takes care of returning to "ROM".
136+
* Hook code must save and restore registers (either everything or according to context).
137+
* The replaced two words must contain an integer number of instructions, must not contain branch target also,
138+
* the copied instructions must not depend on PC (such as branches, ldr, adr, etc).
139+
*
140+
* @param orig original "ROM" address, must actually be RAM mapped there
141+
* @param new address of hook code in RAM
142+
* @param origram RAM representation of 'orig' (that can be written)
143+
*/
144+
void place_fw_hook_t2_64b(unsigned orig, void *new, unsigned origram);
145+
146+
/**
147+
* Version of <code>place_fw_hook_t2_64b</code> for non-hook use.
148+
*
149+
* @param new address of replacement code in RAM
150+
* @param origram address of code in RAM, typically in a copied 64kB ROM page
151+
*/
152+
void place_fw_patch_t2_64b(void *new, unsigned origram);
153+
154+
#endif

0 commit comments

Comments
 (0)