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.shared.vayu;
37
38 import xdc.rov.ViewInfo;
39
40 import xdc.runtime.Assert;
41
42 /*!
43 * ======== Mmu ========
44 * DSP Memory Management Unit (MMU0) Manager.
45 *
46 * This module allows the processor to map a virtual address to a
47 * different physical address and enable/disable the MMU. It does this
48 * through a translation table in memory. The translation table is
49 * 16KB and manages only the first level descriptor table. Each entry
50 * in the table defines the memory translation of a page of size 1MB
51 * (or 16MB if using supersections).
52 *
53 * By default, the MMU translation table is initialized with
54 * entries for every memory segment defined in the platform.
55 * Entries are also added for the peripheral addresses used by
56 * SYS/BIOS (i.e. Timers, Interrupt controller).
57 *
58 * The translation table is placed in
59 * an output section called "ti.sysbios.family.shared.vayu.mmuTableSection".
60 * This section is placed into the platform's default dataMemory and
61 * in order to minimize object file size, specified to not be initialized
62 * via the "NOLOAD" type on GNU compilers and "NOINIT" on TI compilers.
63 *
64 * This module does not manage the second level descriptor tables.
65 * A 'SECTION' mapped access requires only a first level fetch. In
66 * this case, there is no need for a second level descriptor table.
67 * A 'PAGE_TABLE' mapped access requires a second level
68 * descriptor table which can be supplied by the user.
69 *
70 * The following is an example of how to place the MMU table
71 * for the address range 0x80000000-0x90000000 in the *.cfg file:
72 *
73 * @p(code)
74 *
75 * var Mmu = xdc.useModule('ti.sysbios.family.shared.vayu.Mmu');
76 *
77 * // Enable the MMU
78 * Mmu.enableMMU = true;
79 *
80 * // descriptor attribute structure
81 * var attrs = {
82 * type: Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
83 * supersection: false
84 * };
85 *
86 * // Set the descriptor for each entry in the address range
87 * for (var i=0x80000000; i < 0x90000000; i = i + 0x00100000) {
88 * // Each 'SECTION' descriptor entry spans a 1MB address range
89 * Mmu.setFirstLevelDescMeta(i, i, attrs);
90 * }
91 *
92 * var memmap = Program.cpu.memoryMap;
93 * var DDR = null;
94 *
95 * // Find DDR in memory map
96 * for (var i=0; i < memmap.length; i++) {
97 * if (memmap[i].name == "DDR") {
98 * DDR = memmap[i];
99 * }
100 * }
101 *
102 * // Place the MMU table in the DDR memory segment if it exists
103 * if (DDR != null) {
104 * var sectionName = "ti.sysbios.family.shared.vayu.mmuTableSection";
105 * Program.sectMap[sectionName] = new Program.SectionSpec();
106 * Program.sectMap[sectionName].type = "NOINIT"; // NOLOAD for GNU Tools
107 * Program.sectMap[sectionName].loadSegment = "DDR";
108 * }
109 * else {
110 * print("No DDR memory segment was found");
111 * }
112 *
113 * @p
114 *
115 * The following is an example of how to add TLB entries and lock them:
116 *
117 * @p(code)
118 * #include <ti/sysbios/family/shared/vayu/Mmu.h>
119 *
120 * Int main()
121 * {
122 * Int i, j;
123 * Bool ret;
124 *
125 * // Add and lock 16 TLB entries. Once the entries are locked, they
126 * // cannot be evicted by the table walking logic when the MMU is enabled.
127 * for (i = 0x90000000, j = 0; j < 16; i+= 0x1000, j++) {
128 * ret = Mmu_writeTLBEntry((Ptr)i, (Ptr)i, Mmu_PageSize_SMALL);
129 * if (!ret) {
130 * // FAILED: Could not lock TLB entry. TLB is full with locked
131 * // entries.
132 * ...
133 * }
134 * }
135 * ...
136 * BIOS_start();
137 * }
138 * @p
139 *
140 * The following is an example of how to unlock and clear TLB entries:
141 *
142 * @p(code)
143 * #include <ti/sysbios/family/shared/vayu/Mmu.h>
144 *
145 * Int func()
146 * {
147 * Int i, j;
148 *
149 * // Unlock all TLB entries by setting locked entries base value to 0
150 * Mmu_setTLBLockBaseValue(0);
151 *
152 * // Clear (or flush) TLB entries pointed to by given virtual address.
153 * for (i = 0x90000000, j = 0; j < 16; i+= 0x1000, j++) {
154 * Mmu_clearTLBEntry((Ptr)i);
155 * }
156 * ...
157 * }
158 * @p
159 *
160 * The following example shows how to add a second level descriptor table:
161 *
162 * @p(code)
163 * #include <ti/sysbios/BIOS.h>
164 * #include <ti/sysbios/family/shared/vayu/Mmu.h>
165 *
166 * #define MMU_LEVEL2DESC_LARGEPAGE 0x1
167 * #define MMU_LEVEL2DESC_SMALLPAGE 0x2
168 *
169 * #pragma DATA_ALIGN(mmuL2Table, 4096); // align to 4KB
170 *
171 * UInt32 mmuL2Table[256];
172 *
173 * Void main(Int argc, Char * argv[])
174 * {
175 * Mmu_FirstLevelDescAttrs attrs;
176 * Int i, j;
177 *
178 * // initialize the second level descriptors
179 * for (i = 0x80000000, j = 0; j < 256; i+= 0x1000, j++) {
180 * mmuL2Table[j] = (i & 0xFFFFF000) | MMU_LEVEL2DESC_SMALLPAGE;
181 *
182 * // For large pages use below line instead:
183 * // mmuL2Table[j] = (i & 0xFFFF0000) | MMU_LEVEL2DESC_LARGEPAGE;
184 * }
185 *
186 * // first level descriptor properites
187 * Mmu_initDescAttrs(&attrs);
188 * attrs.type = Mmu_FirstLevelDesc_PAGE_TABLE; // set to a page table descriptor
189 *
190 * // Set the first level descriptor for the virtual address 0x80000000.
191 * // No need to disable the MMU. The API should internally disable and
192 * // re-enable it.
193 * Mmu_setFirstLevelDesc((Ptr)0x80000000, &mmuL2Table, &attrs);
194 *
195 * BIOS_start();
196 * }
197 *
198 * ...
199 * @p
200 *
201 * Notes:
202 * @p(blist)
203 * -There are size and alignment requirements on the second
204 * level descriptor tables depending on the page size.
205 * -See the SoC Reference Manual for more info.
206 * @p
207 *
208 * @p(html)
209 * <h3> Calling Context </h3>
210 * <table border="1" cellpadding="3">
211 * <colgroup span="1"></colgroup> <colgroup span="5" align="center">
212 * </colgroup>
213 *
214 * <tr><th> Function </th><th> Hwi </th><th> Swi </th>
215 * <th> Task </th><th> Main </th><th> Startup </th></tr>
216 * <!-- -->
217 * <tr><td> {@link #clearTLBEntry}</td><td> N </td><td> Y </td>
218 * <td> Y </td><td> Y </td><td> Y </td></tr>
219 * <tr><td> {@link #disable} </td><td> N </td><td> Y </td>
220 * <td> Y </td><td> Y </td><td> Y </td></tr>
221 * <tr><td> {@link #enable} </td><td> N </td><td> Y </td>
222 * <td> Y </td><td> Y </td><td> Y </td></tr>
223 * <tr><td> {@link #initDescAttrs} </td><td> Y </td><td> Y </td>
224 * <td> Y </td><td> Y </td><td> Y </td></tr>
225 * <tr><td> {@link #isEnabled} </td><td> Y </td><td> Y </td>
226 * <td> Y </td><td> Y </td><td> Y </td></tr>
227 * <tr><td> {@link #setFirstLevelDesc}</td><td> N </td><td> Y </td>
228 * <td> Y </td><td> Y </td><td> Y </td></tr>
229 * <tr><td> {@link #setTLBLockBaseValue}</td><td> N </td><td> Y </td>
230 * <td> Y </td><td> Y </td><td> Y </td></tr>
231 * <tr><td> {@link #writeTLBEntry}</td><td> N </td><td> Y </td>
232 * <td> Y </td><td> Y </td><td> Y </td></tr>
233 * <tr><td colspan="6"> Definitions: <br />
234 * <ul>
235 * <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
236 * <li> <b>Swi</b>: API is callable from a Swi thread. </li>
237 * <li> <b>Task</b>: API is callable from a Task thread. </li>
238 * <li> <b>Main</b>: API is callable during any of these phases: </li>
239 * <ul>
240 * <li> In your module startup after this module is started
241 * (e.g. Cache_Module_startupDone() returns TRUE). </li>
242 * <li> During xdc.runtime.Startup.lastFxns. </li>
243 * <li> During main().</li>
244 * <li> During BIOS.startupFxns.</li>
245 * </ul>
246 * <li> <b>Startup</b>: API is callable during any of these phases:</li>
247 * <ul>
248 * <li> During xdc.runtime.Startup.firstFxns.</li>
249 * <li> In your module startup before this module is started
250 * (e.g. Cache_Module_startupDone() returns FALSE).</li>
251 * </ul>
252 * </ul>
253 * </td></tr>
254 *
255 * </table>
256 * @p
257 */
258
259 @Template ("./Mmu.xdt")
260 @ModuleStartup
261 @DirectCall
262
263 module Mmu
264 {
265
266
267 /*! @_nodoc */
268 metaonly struct PageView {
269 String Type;
270 Ptr AddrVirtual;
271 Ptr AddrPhysical;
272 Ptr Level2TablePtr;
273 Bool SuperSection;
274 };
275
276 @Facet
277 metaonly config ViewInfo.Instance rovViewInfo =
278 ViewInfo.create({
279 viewMap: [
280 ['0x0-0x7FFFFFFF', {
281 type: ViewInfo.MODULE_DATA,
282 viewInitFxn: 'viewPages1',
283 structName: 'PageView'
284 }],
285 ['0x80000000-0x9FFFFFFF', {
286 type: ViewInfo.MODULE_DATA,
287 viewInitFxn: 'viewPages2',
288 structName: 'PageView'
289 }],
290 ['0xA0000000-0xBFFFFFFF', {
291 type: ViewInfo.MODULE_DATA,
292 viewInitFxn: 'viewPages3',
293 structName: 'PageView'
294 }],
295 ['0xC0000000-0xDFFFFFFF', {
296 type: ViewInfo.MODULE_DATA,
297 viewInitFxn: 'viewPages4',
298 structName: 'PageView'
299 }],
300 ['0xE0000000-0xFFFFFFFF', {
301 type: ViewInfo.MODULE_DATA,
302 viewInitFxn: 'viewPages5',
303 structName: 'PageView'
304 }]
305 ]
306 });
307
308 /*!
309 * First Level descriptors
310 *
311 * Different descriptor type encodings:
312 * 0b00 -> Invalid or Fault entry
313 * 0b01 -> Page table entry
314 * 0b10 -> Section descriptor
315 */
316 enum FirstLevelDesc {
317 FirstLevelDesc_FAULT = 0, /*! Virtual address is unmapped */
318 FirstLevelDesc_PAGE_TABLE = 1, /*! Page table addr descriptor */
319 FirstLevelDesc_SECTION = 2 /*! Section descriptor */
320 };
321
322 /*!
323 * Page size
324 */
325 enum PageSize {
326 PageSize_SECTION = 0, /*! Section (1 MB) */
327 PageSize_LARGE = 1, /*! Large page (64 KB) */
328 PageSize_SMALL = 2, /*! Small page (4 KB) */
329 PageSize_SUPERSECTION = 3 /*! Supersection (16 MB) */
330 };
331
332 /*!
333 * Structure for setting first level descriptor entries
334 *
335 * See the 'Memory Management Units' section of the device TRM for
336 * more details.
337 */
338 struct FirstLevelDescAttrs {
339 FirstLevelDesc type; /*! first level descriptor type */
340 Bool supersection; /*! is a supersection */
341 };
342
343
344
345 /*!
346 * ======== A_nullPointer ========
347 * Assert raised when a pointer is null
348 */
349 config Assert.Id A_nullPointer = {
350 msg: "A_nullPointer: Pointer is null"
351 };
352
353 /*!
354 * ======== A_unknownDescType ========
355 * Assert raised when the descriptor type is not recognized.
356 */
357 config Assert.Id A_unknownDescType = {
358 msg: "A_unknownDescType: Descriptor type is not recognized"
359 };
360
361 /*!
362 * ======== A_baseValueOutOfRange ========
363 * Assert raised when TLB lock entries base value out of range
364 */
365 config Assert.Id A_baseValueOutOfRange = {
366 msg: "A_baseValueOutOfRange: TLB lock entries base value out of range"
367 };
368
369 /*! default descriptor attributes structure */
370 config FirstLevelDescAttrs defaultAttrs = {
371 type: FirstLevelDesc_SECTION,
372 supersection: false,
373 };
374
375 /*!
376 * ======== enableMMU ========
377 * Configuration parameter to enable MMU.
378 */
379 config Bool enableMMU = false;
380
381 /*!
382 * ======== baseAddr ========
383 * MMU base address.
384 *
385 * If not specified, will be automatically set at runtime.
386 */
387 config Regs *baseAddr = null;
388
389 /*!
390 * @_nodoc
391 * MMU Registers.
392 */
393 struct Regs {
394 UInt32 REVISION; /*! 0x000 */
395 UInt32 hole1[3]; /*! 0x004-0x00C */
396 UInt32 SYSCONFIG; /*! 0x010 */
397 UInt32 SYSSTATUS; /*! 0x014 */
398 UInt32 IRQSTATUS; /*! 0x018 */
399 UInt32 IRQENABLE; /*! 0x01C */
400 UInt32 hole2[8]; /*! 0x020-0x03C */
401 UInt32 WALKING_ST; /*! 0x040 */
402 UInt32 CNTL; /*! 0x044 */
403 UInt32 FAULT_AD; /*! 0x048 */
404 UInt32 TTB; /*! 0x04C */
405 UInt32 LOCK; /*! 0x050 */
406 UInt32 LD_TLB; /*! 0x054 */
407 UInt32 CAM; /*! 0x058 */
408 UInt32 RAM; /*! 0x05C */
409 UInt32 GFLUSH; /*! 0x060 */
410 UInt32 FLUSH_ENTRY; /*! 0x064 */
411 UInt32 READ_CAM; /*! 0x068 */
412 UInt32 READ_RAM; /*! 0x06C */
413 UInt32 EMU_FAULT_AD; /*! 0x070 */
414 UInt32 hole3[3]; /*! 0x074-0x07C */
415 UInt32 FAULT_PC; /*! 0x080 */
416 UInt32 FAULT_STATUS; /*! 0x084 */
417 UInt32 GPR; /*! 0x088 */
418 UInt32 BYPASS_REGION1_ADDR; /*! 0x090 */
419 UInt32 BYPASS_REGION1_SIZE; /*! 0x094 */
420 UInt32 BYPASS_REGION2_ADDR; /*! 0x098 */
421 UInt32 BYPASS_REGION2_SIZE; /*! 0x09C */
422 UInt32 BYPASS_REGION3_ADDR; /*! 0x0A0 */
423 UInt32 BYPASS_REGION3_SIZE; /*! 0x0A4 */
424 UInt32 BYPASS_REGION4_ADDR; /*! 0x0A8 */
425 UInt32 BYPASS_REGION4_SIZE; /*! 0x0AC */
426 };
427
428 /*!
429 * ======== numTLBEntries ========
430 * Number of TLB Cache entries.
431 */
432 config UInt numTLBEntries = 32;
433
434 /*!
435 * ======== setFirstLevelDescMeta ========
436 * Statically sets the descriptor for the virtual address.
437 *
438 * The first level table entry for the virtual address is mapped
439 * to the physical address or points to the level 2 descriptor
440 * table. The descriptor table is effective when the MMU is enabled.
441 *
442 * @param(virtualAddr) The modified virtual address
443 * @param(phyAddr) The physical address
444 * @param(attrs) Pointer to first level descriptor attribute struct
445 */
446 metaonly Void setFirstLevelDescMeta(Ptr virtualAddr, Ptr phyAddr,
447 FirstLevelDescAttrs attrs);
448
449 /*!
450 * ======== disable ========
451 * Disables the mmu.
452 *
453 * If the MMU is already disabled, then simply return.
454 * Otherwise this function does the following:
455 * If the L1 data cache is enabled, write back invalidate all
456 * of L1 data cache. If the L1 program cache is enabled,
457 * invalidate all of L1 program cache. This function does not
458 * change the cache L1 data/program settings. If the L2 unified
459 * cache is enabled, it is written back and invalidated.
460 * This function also disables the table walking logic and
461 * performs a global TLB flush. The global TLB flush does not
462 * affect protected TLB entries.
463 *
464 * @a(Note)
465 * The MMU hardware does not permit disabling the MMU
466 * while an interrupt is pending. If this API is called with
467 * an interrupt still pending, the MMU will generate an error.
468 */
469 Void disable();
470
471 /*!
472 * ======== enable ========
473 * Enables the MMU.
474 *
475 * If the MMU is already enabled, then simply return.
476 * Otherwise this function does the following:
477 * If the L1 program cache is enabled, invalidate all of L1
478 * program cache. This function does not change the L1
479 * data/program cache settings. If the L2 unified cache is
480 * enabled, it is written back and invalidated.
481 * This function also explicitly enables the table walking
482 * logic and performs a global TLB flush. The global TLB
483 * flush does not affect protected TLB entries.
484 */
485 Void enable();
486
487 /*!
488 * ======== initDescAttrs() ========
489 * Initializes the first level descriptor attribute structure
490 *
491 * @param(attrs) Pointer to first level descriptor attribute struct
492 */
493 Void initDescAttrs(FirstLevelDescAttrs *attrs);
494
495 /*!
496 * ======== isEnabled ========
497 * Determines if the MMU is enabled
498 */
499 Bool isEnabled();
500
501 /*!
502 * ======== setFirstLevelDesc ========
503 * Sets the descriptor for the virtual address.
504 *
505 * The first level table entry for the virtual address is mapped
506 * to the physical address with the attributes specified. The
507 * descriptor table is effective when the MMU is enabled.
508 *
509 * @a(Note)
510 * This API internally disables and re-enables the MMU.
511 * Since the MMU hardware does not permit disabling the MMU
512 * while an interrupt is pending, this API should not be called
513 * with any interrupts still pending. It is recommended to
514 * call this function from within main() before calling
515 * BIOS_start().
516 *
517 * @param(virtualAddr) The modified virtual address
518 * @param(phyAddr) The physical address
519 * @param(attrs) Pointer to first level descriptor attribute struct
520 */
521 Void setFirstLevelDesc(Ptr virtualAddr, Ptr phyAddr,
522 FirstLevelDescAttrs *attrs);
523
524 /*!
525 * ======== writeTLBEntry ========
526 * Manually adds a TLB entry and locks it
527 *
528 * This function ready the TLB lock base value and uses it to
529 * select a victim TLB entry to write to. Once the new TLB
530 * entry is written, it increments the TLB lock base value to
531 * lock the entry. The TLB entries added using this function
532 * are marked as protected and therefore are not affected by
533 * global TLB flush operations.
534 *
535 * @a(Note)
536 * Due to the mechanism used to lock TLB entries, it is
537 * not possible to unlock a random locked TLB entry. All TLB
538 * entries in front need to be unlocked first. For example,
539 * if the first 4 TLB entries (i.e. TLB index 0, 1, 2 & 3) are
540 * locked and the second TLB entry (i.e. TLB index 1) needs to
541 * be unlocked, then the TLB entries with indices 1, 2 & 3
542 * have to all be unlocked in order to unlock TLB entry
543 * with index 1. This can be done by calling
544 * {@link #setTLBLockBaseValue}() function.
545 *
546 * @a(Note)
547 * This API internally disables and re-enables the MMU.
548 * Since the MMU hardware does not permit disabling the MMU
549 * while an interrupt is pending, this API should not be called
550 * with any interrupts still pending. It is recommended to
551 * call this function from within main() before calling
552 * BIOS_start().
553 *
554 * @param(virtualAddr) The modified virtual address
555 * @param(phyAddr) The physical address
556 * @param(size) TLB page size.
557 * @b(returns) TRUE - Entry succesfully written and locked, OR,
558 * FALSE - Write failed. No free TLB entries.
559 */
560 Bool writeTLBEntry(Ptr virtualAddr, Ptr physicalAddr, PageSize size);
561
562 /*!
563 * ======== clearTLBEntry ========
564 * Clears (or flushes) a TLB entry
565 *
566 * This function flushes all TLB entries (including protected
567 * entries) pointed to by the given virtual address. It can be
568 * used to delete a TLB entry after it has been unlocked.
569 *
570 * @a(Note)
571 * This API internally disables and re-enables the MMU.
572 * Since the MMU hardware does not permit disabling the MMU
573 * while an interrupt is pending, this API should not be called
574 * with any interrupts still pending.
575 *
576 * @param(virtualAddr) The modified virtual Address
577 */
578 Void clearTLBEntry(Ptr virtualAddr);
579
580 /*!
581 * ======== setTLBLockBaseValue ========
582 * Sets the TLB locked entries base value to the given value.
583 *
584 * First n TLB entries (with n < total number of TLB entries) can be
585 * protected from being overwritten with new translations. n is equal
586 * to the TLB locked entries base value.
587 *
588 * This function can be used to unlock TLB entries. Once an
589 * entry is unlocked, it can be cleared using {@link #clearTLBEntry}()
590 * function.
591 *
592 * @a(Note)
593 * This API internally disables and re-enables the MMU.
594 * Since the MMU hardware does not permit disabling the MMU
595 * while an interrupt is pending, this API should not be called
596 * with any interrupts still pending.
597 *
598 * @param(basevalue) TLB locked entries base value
599 */
600 Void setTLBLockBaseValue(UInt basevalue);
601
602 internal:
603
604 /*! static array to hold first level dscriptor table */
605 metaonly config UInt32 tableBuf[];
606
607 /*!
608 * ======== init ========
609 * initialize mmu registers
610 */
611 Void init();
612
613 /*! function generated to initialize first level descriptor table */
614 Void initTableBuf(UInt32 *mmuTableBuf);
615
616 /*! Module state */
617 struct Module_State {
618 volatile Regs *regs;
619 UInt32 tableBuf[]; /*! 16KB array for first-level descriptors */
620 }
621 }