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 package ti.sysbios.family.arm.a15;
37
38 import xdc.rov.ViewInfo;
39
40 /*!
41 * ======== Mmu ========
42 * Memory Management Unit Manager.
43 *
44 * This module allows the ARM processor to map a 32-bit virtual address
45 * to a 40-bit physical address (supports Large physical address extensions)
46 * and enable/disable the MMU. It does this through translation tables
47 * in memory. The MMU hardware supports upto 3-levels of translation tables.
48 * This module only supports the first 2 levels of translation tables.
49 * The level1 translation table is a 32B descriptor table comprising of
50 * four 64bit entries. There can be upto 4 level2 translation tables,
51 * each 4KB in size and comprising of 512 64bit entries.
52 *
53 * Each entry in the level1 table either gives the base address and
54 * defines the attributes of a memory area of size 1GB or gives the
55 * address of the next level of translation table and some attributes
56 * for that translation.
57 *
58 * Each entry in the level2 table either gives the base address and
59 * defines the attributes of a memory area of size 2MB or gives the
60 * address of the next level of translation table and some attributes
61 * for that translation.
62 *
63 * By default, the MMU level1 and level2 translation tables are initialized
64 * with cache-enabled entries for every memory-segment defined in the
65 * platform (see {@link #cachePlatformMemory}). Cache-disabled entries are
66 * also added for the peripheral addresses used by SYS/BIOS
67 * (i.e. Timers, Interrupt controller).
68 *
69 * The level1 translation table is placed in an output section called
70 * "ti.sysbios.family.arm.a15.mmuFirstLevelTableSection". Each of the
71 * level2 translation table is placed in output sections called
72 * "ti.sysbios.family.arm.a15.mmuSecondLevelTableSection0",
73 * "ti.sysbios.family.arm.a15.mmuSecondLevelTableSection1",
74 * "ti.sysbios.family.arm.a15.mmuSecondLevelTableSection2", and
75 * "ti.sysbios.family.arm.a15.mmuSecondLevelTableSection3". These
76 * sections are placed into the platform's default dataMemory and
77 * in order to minimize object file size,
78 * specified to not be initialized via the "NOLOAD" type on GNU compilers
79 * and "NOINIT" on TI compilers.
80 *
81 * This module does not manage the third level descriptor tables.
82 *
83 * The following is an example of how to place the MMU table
84 * and how to enable L1/L2 data caching for the address range
85 * 0x80000000-0x90000000 in the *.cfg file:
86 *
87 * @p(code)
88 *
89 * var Mmu = xdc.useModule('ti.sysbios.family.arm.a15.Mmu');
90 *
91 * // descriptor attribute structure
92 * var attrs = new Mmu.DescriptorAttrs();
93 *
94 * Mmu.initDescAttrsMeta(attrs);
95 * attrs.type = Mmu.DescriptorType_BLOCK; // BLOCK descriptor
96 * attrs.shareable = 3; // inner-sharerable
97 * attrs.attrIndx = 2; // MAIR0 Byte2 describes
98 * // memory attributes for
99 * // this level2 entry
100 *
101 * // write memory region attribute in mairRegAttr[2] i.e. MAIR0 Reg Byte2
102 * Mmu.setMAIRMeta(2, 0xFF); // Mark mem regions as cacheable
103 *
104 * // Set the descriptor for each entry in the address range
105 * for (var i=0x80000000; i < 0x90000000; i = i + 0x00200000) {
106 * // Each 'BLOCK' descriptor entry spans a 2MB address range
107 * Mmu.setSecondLevelDescMeta(i, i, attrs);
108 * }
109 *
110 * var memmap = Program.cpu.memoryMap;
111 * var DDR = null;
112 *
113 * // Find DDR in memory map
114 * for (var i=0; i < memmap.length; i++) {
115 * if (memmap[i].name == "DDR") {
116 * DDR = memmap[i];
117 * }
118 * }
119 *
120 * // Place the MMU table in the DDR memory segment if it exists
121 * if (DDR != null) {
122 * var sectionName =
123 * "ti.sysbios.family.arm.a15.mmuSecondLevelTableSection2";
124 * Program.sectMap[sectionName] = new Program.SectionSpec();
125 * Program.sectMap[sectionName].type = "NOLOAD";
126 * Program.sectMap[sectionName].loadSegment = "DDR";
127 * }
128 * else {
129 * print("No DDR memory segment was found");
130 * }
131 *
132 * @p
133 *
134 * The following example demonstrates how to add a peripheral's address
135 * to the MMU table so that it can be accessed by code at runtime:
136 *
137 * @p(code)
138 * var Cache = xdc.useModule('ti.sysbios.family.arm.a15.Cache');
139 * var Mmu = xdc.useModule('ti.sysbios.family.arm.a15.Mmu');
140 *
141 * // Enable the cache
142 * Cache.enableCache = true;
143 *
144 * // Enable the MMU (Required for L1/L2 data caching)
145 * Mmu.enableMMU = true;
146 *
147 * // descriptor attribute structure
148 * var peripheralAttrs = new Mmu.DescriptorAttrs();
149 *
150 * Mmu.initDescAttrsMeta(peripheralAttrs);
151 *
152 * peripheralAttrs.type = Mmu.DescriptorType_BLOCK; // BLOCK descriptor
153 * peripheralAttrs.noExecute = true; // not executable
154 * peripheralAttrs.accPerm = 0; // read/write at PL1
155 * peripheralAttrs.attrIndx = 1; // MAIR0 Byte1 describes
156 * // memory attributes for
157 * // each BLOCK MMU entry
158 *
159 * // write memory region attribute in mairRegAttr[1] i.e. MAIR0 Reg Byte1
160 * Mmu.setMAIRMeta(1, 0x0); // Mark mem regions as strongly ordered memory
161 *
162 * // Define the base address of the 2 MB page
163 * // the peripheral resides in.
164 * var peripheralBaseAddr = 0xa0400000;
165 *
166 * // Configure the corresponding MMU page descriptor accordingly
167 * Mmu.setSecondLevelDescMeta(peripheralBaseAddr,
168 * peripheralBaseAddr,
169 * peripheralAttrs);
170 * @p
171 *
172 * The following example demonstrates how to modify the first level MMU entry
173 * at runtime. This example changes the descriptor type of the first level
174 * table entry from Table (default) to Block (maps memory region of size 1GB).
175 *
176 * @p(code)
177 * ...
178 *
179 * Void main(Int argc, Char * argv[])
180 * {
181 * Mmu_DescriptorAttrs attrs;
182 * Mmu_initDescAttrs(&attrs);
183 *
184 * attrs.type = Mmu_DescriptorType_BLOCK;
185 * attrs.shareable = 0; // non-shareable
186 * attrs.accPerm = 1; // read/write at any privelege level
187 * attrs.attrIndx = 3; // Use MAIR0 Register Byte 3 for
188 * // determining the memory attributes
189 * // for each MMU entry
190 *
191 * // attrIndx[2] = 0b0 selects MAIR0
192 * // attrIndx[1:0] = 0b11 selects Byte 3 in MAIR0
193 * //
194 * // A value of 0x4F is written to Byte 3 of MAIR0. This marks the memory
195 * // as Normal Memory that is outer non-cacheable and inner write-back
196 * // cacheable for both reads and writes.
197 *
198 * Mmu_setMAIR(3, 0x4F);
199 *
200 * // Update the first level table's MMU entry for 0x80000000 with the
201 * // new attributes.
202 * Mmu_setFirstLevelDesc((Ptr)0x80000000, (UInt64)0x80000000, &attrs);
203 * }
204 *
205 * @p
206 *
207 * The following example demonstrates how to modify the memory attributes
208 * for a second level MMU entry at runtime.
209 *
210 * @p(code)
211 * ...
212 *
213 * Void main(Int argc, Char * argv[])
214 * {
215 * Mmu_DescriptorAttrs attrs;
216 * Mmu_initDescAttrs(&attrs);
217 *
218 * attrs.type = Mmu_DescriptorType_BLOCK;
219 * attrs.shareable = 0; // non-shareable
220 * attrs.accPerm = 1; // read/write at any privelege level
221 * attrs.attrIndx = 4; // Use MAIR1 Register Byte 0 for
222 * // determining the memory attributes
223 * // for each MMU entry
224 *
225 * // attrIndx[2] = 0b1 selects MAIR1
226 * // attrIndx[1:0] = 0b00 selects Byte 0 in MAIR1
227 * //
228 * // A value of 0x4F is written to Byte 0 of MAIR1. This marks the memory
229 * // as Normal Memory that is outer non-cacheable and inner write-back
230 * // cacheable for both reads and writes.
231 *
232 * Mmu_setMAIR(4, 0x4F);
233 *
234 * // Update the MMU entry for 0x80000000 with the new attributes.
235 * Mmu_setSecondLevelDesc((Ptr)0x80000000, (UInt64)0x80000000, &attrs);
236 * }
237 *
238 * @p
239 *
240 * Notes:
241 * @p(blist)
242 * -There are size and alignment requirements on the third
243 * level descriptor tables depending on the page size.
244 * -See the {@link http://infocenter.arm.com/help/topic/com.arm.doc.ddi0406c/index.html ARM v7AR Architecture Reference Manual}
245 * for more info.
246 * @p
247 *
248 */
249
250 @Template ("./Mmu.xdt")
251 @ModuleStartup
252
253 module Mmu
254 {
255 const UInt NUM_LEVEL1_ENTRIES = 4;
256
257 const UInt NUM_LEVEL2_ENTRIES = 512;
258
259
260
261 /*! @_nodoc */
262 metaonly struct PageView {
263 String Type;
264 String AddrVirtual;
265 String AddrPhysical;
266 String NextLevelTablePtr;
267 Bool NSTable;
268 String APTable;
269 Bool XNTable;
270 Bool PXNTable;
271 Bool NoExecute;
272 Bool PrivNoExecute;
273 Bool Contiguous;
274 Bool NotGlobal;
275 Bool AccessFlag;
276 String Shareable;
277 String AccessPerm;
278 Bool NonSecure;
279 String MemAttr;
280 String AttrIndx;
281 };
282
283 @Facet
284 metaonly config ViewInfo.Instance rovViewInfo =
285 ViewInfo.create({
286 viewMap: [
287 ['Level1View', {
288 type: ViewInfo.MODULE_DATA,
289 viewInitFxn: 'viewLevel1Page',
290 structName: 'PageView'
291 }],
292 ['Level2View', {
293 type: ViewInfo.TREE_TABLE,
294 viewInitFxn: 'viewLevel2Page',
295 structName: 'PageView'
296 }]
297 ]
298 });
299
300 /*!
301 * ======== First and Second Level descriptors ========
302 *
303 * Different descriptor type encodings:
304 * @p(blist)
305 * - Invalid or Fault entry (0b00 or 0b10)
306 * - Block descriptor entry (0b01)
307 * - Table descriptor entry (0b11)
308 * @p
309 *
310 * If a First-level table contains only one entry, it would be skipped,
311 * and the TTBR points to the Second-level table. This happens if the
312 * VA address range is 30 bits or less.
313 */
314 enum DescriptorType {
315 DescriptorType_INVALID0 = 0, /*! Virtual address is unmapped */
316 DescriptorType_BLOCK = 1, /*! Block descriptor */
317 DescriptorType_INVALID1 = 2, /*! Virtual address is unmapped */
318 DescriptorType_TABLE = 3 /*! Next-level table address */
319 };
320
321 /*!
322 * Structure for setting first and second level descriptor entries
323 *
324 * nsTable, apTable, xnTable and pxnTable fields are used only for
325 * DescriptorType.TABLE
326 *
327 * noExecute, privNoExecute, contiguous, notGlobal, accessFlag, shareable,
328 * accPerm, nonSecure and attrIndx fields are used only for
329 * DescriptorType.BLOCK
330 */
331 struct DescriptorAttrs {
332 DescriptorType type; /*! first level descriptor type */
333 Bool nsTable; /*! security level for subsequent levels */
334 UInt8 apTable; /*! access perm limit for subsequent levels */
335 Bool xnTable; /*! XN limit for subsequent levels */
336 Bool pxnTable; /*! PXN limit for subsequent levels */
337 Bool noExecute; /*! execute-never bit */
338 Bool privNoExecute; /*! privileged execute-never bit */
339 Bool contiguous; /*! hint bit indicating 16 adjacent table
340 entries point to contiguos memory */
341 Bool notGlobal; /*! not global bit */
342 Bool accessFlag; /*! access flag */
343 UInt8 shareable; /*! shareability field value 0-3 */
344 UInt8 accPerm; /*! access permission bits value 0-3 */
345 Bool nonSecure; /*! non-secure bit */
346 UInt8 attrIndx; /*! stage 1 memory attributes index field for
347 the indicated MAIRn register value 0-7 */
348 UInt8 reserved; /*! Bits[58:55] reserved for software use */
349 };
350
351 /*!
352 * ======== A_nullPointer ========
353 * Assert raised when a pointer is null
354 */
355 config xdc.runtime.Assert.Id A_nullPointer = {
356 msg: "A_nullPointer: Pointer is null"
357 };
358
359 /*!
360 * ======== A_unknownDescType ========
361 * Assert raised when the descriptor type is not recognized.
362 */
363 config xdc.runtime.Assert.Id A_unknownDescType =
364 {msg: "A_unknownDescType: Descriptor type is not recognized"};
365
366 /*! default descriptor attributes structure */
367 config DescriptorAttrs defaultAttrs = {
368 type: DescriptorType_TABLE,
369 nsTable: false,
370 apTable: 0,
371 xnTable: false,
372 pxnTable: false,
373 noExecute: false,
374 privNoExecute: false,
375 contiguous: false, 376
377 notGlobal: false,
378 accessFlag: true,
379 shareable: 0,
380 accPerm: 0,
381 nonSecure: false,
382 attrIndx: 0, 383
384 reserved: 0
385 };
386
387 /*!
388 * ======== enableMMU ========
389 * Configuration parameter to enable MMU.
390 */
391 config Bool enableMMU = true;
392
393 /*!
394 * ======== cachePlatformMemory ========
395 * Flag to automatically mark platform's code/data/stack memory as
396 * cacheable in MMU descriptor table
397 *
398 * By default, all memory regions defined in the platform an
399 * application is built with are marked as cacheable.
400 *
401 * @see xdc.bld.Program#platform
402 *
403 * If manual configuration of memory regions is required, set
404 * this config parameter to 'false'.
405 */
406 metaonly config Bool cachePlatformMemory = true;
407
408 /*!
409 * ======== setMAIRMeta ========
410 * Statically sets the memory attribute encoding in the MAIRn register.
411 *
412 * MAIR0 and MAIR1 provide the memory attribute encodings to the possible
413 * {@link #DescriptorAttrs attrIndx} values in a Long-descriptor format
414 * translation table entry for stage 1 translations (see {@link #setMAIR}
415 * for more details).
416 *
417 * @param(attrIndx) Select appropriate MAIR register (0 or 1)
418 * and byte offset within selected register
419 * @param(attr) Memory attribute encoding
420 */
421 metaonly Void setMAIRMeta(UInt attrIndx, UInt attr);
422
423 /*!
424 * ======== initDescAttrsMeta ========
425 * Initializes the descriptor attribute structure
426 *
427 * @param(attrs) Pointer to descriptor attribute struct
428 */
429 metaonly Void initDescAttrsMeta(DescriptorAttrs *descAttrs);
430
431 /*!
432 * ======== setFirstLevelDescMeta ========
433 * Statically sets the descriptor for the virtual address.
434 *
435 * The first level table entry for the virtual address is mapped
436 * to the physical address with the attributes specified. The
437 * descriptor table is effective when the MMU is enabled.
438 *
439 * @see ti.sysbios.family.arm.a15.Mmu
440 *
441 * @param(virtualAddr) The modified virtual address
442 * @param(phyAddr) The physical address
443 * @param(attrs) Pointer to first level descriptor attribute struct
444 */
445 metaonly Void setFirstLevelDescMeta(Ptr virtualAddr, UInt64 phyAddr,
446 DescriptorAttrs attrs);
447
448 /*!
449 * ======== setSecondLevelDescMeta ========
450 * Statically sets the descriptor for the virtual address.
451 *
452 * The second level table entry for the virtual address is mapped
453 * to the physical address with the attributes specified. The
454 * descriptor table is effective when the MMU is enabled.
455 *
456 * @see ti.sysbios.family.arm.a15.Mmu
457 *
458 * @param(virtualAddr) The modified virtual address
459 * @param(phyAddr) The physical address
460 * @param(attrs) Pointer to second level descriptor attribute struct
461 */
462 metaonly Void setSecondLevelDescMeta(Ptr virtualAddr, UInt64 phyAddr,
463 DescriptorAttrs attrs);
464
465 /*!
466 * ======== disable ========
467 * Disables the MMU.
468 *
469 * If the MMU is already disabled, then simply return.
470 * Otherwise this function does the following:
471 * @p(blist)
472 * - If the L1 data cache is enabled, write back invalidate all
473 * of L1 data cache.
474 * - If the L1 program cache is enabled, invalidate all of L1
475 * program cache.
476 * @p
477 *
478 * @a(Note)
479 * This function does not change the cache L1 data/program settings.
480 */
481 @DirectCall
482 Void disable();
483
484 /*!
485 * ======== enable ========
486 * Enables the MMU.
487 *
488 * If the MMU is already enabled, then simply return.
489 * Otherwise this function does the following:
490 * @p(blist)
491 * If the L1 program cache is enabled, invalidate all of L1
492 * program cache.
493 * @p
494 *
495 * @a(Note)
496 * This function does not change the L1 data/program cache settings.
497 */
498 @DirectCall
499 Void enable();
500
501 /*!
502 * ======== initDescAttrs() ========
503 * Initializes the descriptor attribute structure
504 *
505 * @param(attrs) Pointer to descriptor attribute struct
506 */
507 @DirectCall
508 Void initDescAttrs(DescriptorAttrs *descAttrs);
509
510 /*!
511 * ======== isEnabled ========
512 * Determines if the MMU is enabled
513 */
514 @DirectCall
515 Bool isEnabled();
516
517 /*!
518 * ======== setMAIR ========
519 * Sets the memory attribute encoding in the MAIRn register.
520 *
521 * MAIR0 and MAIR1 provide the memory attribute encodings to the possible
522 * {@link #DescriptorAttrs attrIndx} values in a long-descriptor format
523 * translation table entry for stage 1 translations.
524 *
525 * {@link #DescriptorAttrs attrIndx}[1:0] selects the ATTRn bit-field in
526 * the selected MAIR register.
527 *
528 * {@link #DescriptorAttrs attrIndx}[2] selects the MAIR register.
529 * @p(blist)
530 * - If {@link #DescriptorAttrs attrIndx}[2] == 0, use MAIR0
531 * - If {@link #DescriptorAttrs attrIndx}[2] == 1, use MAIR1
532 * @p
533 *
534 * Memory Attribute Indirection Register (MAIR) 0 and 1 bit assignments:
535 * @p(code)
536 * |31 | 24|23 | 16|15 | 8|7 | 0|
537 * --------------------------------------------------------------
538 * MAIR0 | ATTR3 | ATTR2 | ATTR1 | ATTR0 |
539 * --------------------------------------------------------------
540 * MAIR1 | ATTR7 | ATTR6 | ATTR5 | ATTR4 |
541 * --------------------------------------------------------------
542 * @p
543 *
544 * SYS/BIOS assigns the following defaults to MAIR0 ATTR0, ATTR1 and ATTR2:
545 * @p(code)
546 * ATTR0 -> 0x44 (mark memory region as non-cacheable normal memory)
547 * ATTR1 -> 0x00 (mark memory region as strongly ordered and non-cacheable)
548 * ATTR2 -> 0xFF (mark memory region as normal memory, RW cacheable and
549 * RW allocate)
550 * @p
551 *
552 * The level1 and level2 MMU Table entries use the above default
553 * attributes created by this module and should preferably not be
554 * changed. Please note that if the default value assigned to ATTR0 is
555 * changed, then the {@link #cachePlatformMemory} config param may not
556 * behave correctly as it uses this attribute to mark the memory as
557 * non-cacheable normal memory. If ATTR1 or ATTR2 are changed, it will
558 * affect all existing MMU Table entries which use ATTR1 or ATTR2.
559 *
560 * For more details on MAIR0 and MAIR1 encodings please refer
561 * {@link http://infocenter.arm.com/help/topic/com.arm.doc.ddi0406c/index.html v7A ARM Architecture Reference Manual}
562 *
563 * @param(attrIndx) Select appropriate MAIR register (0 or 1)
564 * and byte offset within the selected register
565 * @param(attr) Memory attribute encoding
566 */
567 @DirectCall
568 Void setMAIR(UInt attrIndx, UInt attr);
569
570 /*!
571 * ======== setFirstLevelDesc ========
572 * Sets the descriptor for the virtual address.
573 *
574 * The first level table entry for the virtual address is mapped
575 * to the physical address with the attributes specified. The
576 * descriptor table is effective when the MMU is enabled.
577 *
578 * @see ti.sysbios.family.arm.a15.Mmu
579 *
580 * @param(virtualAddr) The modified virtual address
581 * @param(phyAddr) The physical address
582 * @param(attrs) Pointer to first level descriptor attribute struct
583 */
584 @DirectCall
585 Void setFirstLevelDesc(Ptr virtualAddr, UInt64 phyAddr,
586 DescriptorAttrs *attrs);
587
588 /*!
589 * ======== setSecondLevelDesc ========
590 * Sets the descriptor for the virtual address.
591 *
592 * The second level table entry for the virtual address is mapped
593 * to the physical address with the attributes specified. The
594 * descriptor table is effective when the MMU is enabled.
595 *
596 * @see ti.sysbios.family.arm.a15.Mmu
597 *
598 * @param(virtualAddr) The modified virtual address
599 * @param(phyAddr) The physical address
600 * @param(attrs) Pointer to second level descriptor attribute struct
601 */
602 @DirectCall
603 Void setSecondLevelDesc(Ptr virtualAddr, UInt64 phyAddr,
604 DescriptorAttrs *attrs);
605
606 internal:
607
608 /*! static array to hold first level dscriptor table */
609 metaonly config UInt32 firstLevelTableBuf[];
610
611 /*! static array to hold second level dscriptor table */
612 metaonly config UInt32 secondLevelTableBuf[NUM_LEVEL1_ENTRIES][];
613
614 /*!
615 * Memory Attribute Indirection Register 0 and 1
616 */
617 config UInt mairRegAttr[8];
618
619 /*!
620 * ======== init ========
621 * initialize mmu registers
622 */
623 Void init();
624
625 /*!
626 * ======== enableAsm ========
627 * Assembly function to enable the MMU.
628 */
629 Void enableAsm();
630
631 /*!
632 * ======== disableAsm ========
633 * Assembly function to disable the MMU.
634 */
635 Void disableAsm();
636
637 /*!
638 * ======== writeMAIRAsm ========
639 */
640 Void writeMAIRAsm(UInt attrIndx, UInt attr);
641
642 /*! function generated to initialize first level descriptor table */
643 Void initFirstLevelTableBuf(UInt64 *firstLevelTableBuf,
644 UInt64 **secondLevelTableBuf);
645
646 /*! function generated to initialize second level descriptor table */
647 Void initSecondLevelTableBuf(UInt64 **secondLevelTableBuf);
648
649 /*! Module state */
650 struct Module_State {
651 652 653
654 UInt64 firstLevelTableBuf[];
655
656 657 658
659 UInt64 secondLevelTableBuf[NUM_LEVEL1_ENTRIES][];
660
661 662 663
664 UInt mairRegAttr[8];
665 }
666 }