| ================================= |
| FR451 MMU LINUX MEMORY MANAGEMENT |
| ================================= |
| |
| ============ |
| MMU HARDWARE |
| ============ |
| |
| FR451 MMU Linux puts the MMU into EDAT mode whilst running. This means that it uses both the SAT |
| registers and the DAT TLB to perform address translation. |
| |
| There are 8 IAMLR/IAMPR register pairs and 16 DAMLR/DAMPR register pairs for SAT mode. |
| |
| In DAT mode, there is also a TLB organised in cache format as 64 lines x 2 ways. Each line spans a |
| 16KB range of addresses, but can match a larger region. |
| |
| |
| =========================== |
| MEMORY MANAGEMENT REGISTERS |
| =========================== |
| |
| Certain control registers are used by the kernel memory management routines: |
| |
| REGISTERS USAGE |
| ====================== ================================================== |
| IAMR0, DAMR0 Kernel image and data mappings |
| IAMR1, DAMR1 First-chance TLB lookup mapping |
| DAMR2 Page attachment for cache flush by page |
| DAMR3 Current PGD mapping |
| SCR0, DAMR4 Instruction TLB PGE/PTD cache |
| SCR1, DAMR5 Data TLB PGE/PTD cache |
| DAMR6-10 kmap_atomic() mappings |
| DAMR11 I/O mapping |
| CXNR mm_struct context ID |
| TTBR Page directory (PGD) pointer (physical address) |
| |
| |
| ===================== |
| GENERAL MEMORY LAYOUT |
| ===================== |
| |
| The physical memory layout is as follows: |
| |
| PHYSICAL ADDRESS CONTROLLER DEVICE |
| =================== ============== ======================================= |
| 00000000 - BFFFFFFF SDRAM SDRAM area |
| E0000000 - EFFFFFFF L-BUS CS2# VDK SLBUS/PCI window |
| F0000000 - F0FFFFFF L-BUS CS5# MB93493 CSC area (DAV daughter board) |
| F1000000 - F1FFFFFF L-BUS CS7# (CB70 CPU-card PCMCIA port I/O space) |
| FC000000 - FC0FFFFF L-BUS CS1# VDK MB86943 config space |
| FC100000 - FC1FFFFF L-BUS CS6# DM9000 NIC I/O space |
| FC200000 - FC2FFFFF L-BUS CS3# MB93493 CSR area (DAV daughter board) |
| FD000000 - FDFFFFFF L-BUS CS4# (CB70 CPU-card extra flash space) |
| FE000000 - FEFFFFFF Internal CPU peripherals |
| FF000000 - FF1FFFFF L-BUS CS0# Flash 1 |
| FF200000 - FF3FFFFF L-BUS CS0# Flash 2 |
| FFC00000 - FFC0001F L-BUS CS0# FPGA |
| |
| The virtual memory layout is: |
| |
| VIRTUAL ADDRESS PHYSICAL TRANSLATOR FLAGS SIZE OCCUPATION |
| ================= ======== ============== ======= ======= =================================== |
| 00004000-BFFFFFFF various TLB,xAMR1 D-N-??V 3GB Userspace |
| C0000000-CFFFFFFF 00000000 xAMPR0 -L-S--V 256MB Kernel image and data |
| D0000000-D7FFFFFF various TLB,xAMR1 D-NS??V 128MB vmalloc area |
| D8000000-DBFFFFFF various TLB,xAMR1 D-NS??V 64MB kmap() area |
| DC000000-DCFFFFFF various TLB 1MB Secondary kmap_atomic() frame |
| DD000000-DD27FFFF various DAMR 160KB Primary kmap_atomic() frame |
| DD040000 DAMR2/IAMR2 -L-S--V page Page cache flush attachment point |
| DD080000 DAMR3 -L-SC-V page Page Directory (PGD) |
| DD0C0000 DAMR4 -L-SC-V page Cached insn TLB Page Table lookup |
| DD100000 DAMR5 -L-SC-V page Cached data TLB Page Table lookup |
| DD140000 DAMR6 -L-S--V page kmap_atomic(KM_BOUNCE_READ) |
| DD180000 DAMR7 -L-S--V page kmap_atomic(KM_SKB_SUNRPC_DATA) |
| DD1C0000 DAMR8 -L-S--V page kmap_atomic(KM_SKB_DATA_SOFTIRQ) |
| DD200000 DAMR9 -L-S--V page kmap_atomic(KM_USER0) |
| DD240000 DAMR10 -L-S--V page kmap_atomic(KM_USER1) |
| E0000000-FFFFFFFF E0000000 DAMR11 -L-SC-V 512MB I/O region |
| |
| IAMPR1 and DAMPR1 are used as an extension to the TLB. |
| |
| |
| ==================== |
| KMAP AND KMAP_ATOMIC |
| ==================== |
| |
| To access pages in the page cache (which may not be directly accessible if highmem is available), |
| the kernel calls kmap(), does the access and then calls kunmap(); or it calls kmap_atomic(), does |
| the access and then calls kunmap_atomic(). |
| |
| kmap() creates an attachment between an arbitrary inaccessible page and a range of virtual |
| addresses by installing a PTE in a special page table. The kernel can then access this page as it |
| wills. When it's finished, the kernel calls kunmap() to clear the PTE. |
| |
| kmap_atomic() does something slightly different. In the interests of speed, it chooses one of two |
| strategies: |
| |
| (1) If possible, kmap_atomic() attaches the requested page to one of DAMPR5 through DAMPR10 |
| register pairs; and the matching kunmap_atomic() clears the DAMPR. This makes high memory |
| support really fast as there's no need to flush the TLB or modify the page tables. The DAMLR |
| registers being used for this are preset during boot and don't change over the lifetime of the |
| process. There's a direct mapping between the first few kmap_atomic() types, DAMR number and |
| virtual address slot. |
| |
| However, there are more kmap_atomic() types defined than there are DAMR registers available, |
| so we fall back to: |
| |
| (2) kmap_atomic() uses a slot in the secondary frame (determined by the type parameter), and then |
| locks an entry in the TLB to translate that slot to the specified page. The number of slots is |
| obviously limited, and their positions are controlled such that each slot is matched by a |
| different line in the TLB. kunmap() ejects the entry from the TLB. |
| |
| Note that the first three kmap atomic types are really just declared as placeholders. The DAMPR |
| registers involved are actually modified directly. |
| |
| Also note that kmap() itself may sleep, kmap_atomic() may never sleep and both always succeed; |
| furthermore, a driver using kmap() may sleep before calling kunmap(), but may not sleep before |
| calling kunmap_atomic() if it had previously called kmap_atomic(). |
| |
| |
| =============================== |
| USING MORE THAN 256MB OF MEMORY |
| =============================== |
| |
| The kernel cannot access more than 256MB of memory directly. The physical layout, however, permits |
| up to 3GB of SDRAM (possibly 3.25GB) to be made available. By using CONFIG_HIGHMEM, the kernel can |
| allow userspace (by way of page tables) and itself (by way of kmap) to deal with the memory |
| allocation. |
| |
| External devices can, of course, still DMA to and from all of the SDRAM, even if the kernel can't |
| see it directly. The kernel translates page references into real addresses for communicating to the |
| devices. |
| |
| |
| =================== |
| PAGE TABLE TOPOLOGY |
| =================== |
| |
| The page tables are arranged in 2-layer format. There is a middle layer (PMD) that would be used in |
| 3-layer format tables but that is folded into the top layer (PGD) and so consumes no extra memory |
| or processing power. |
| |
| +------+ PGD PMD |
| | TTBR |--->+-------------------+ |
| +------+ | | : STE | |
| | PGE0 | PME0 : STE | |
| | | : STE | |
| +-------------------+ Page Table |
| | | : STE -------------->+--------+ +0x0000 |
| | PGE1 | PME0 : STE -----------+ | PTE0 | |
| | | : STE -------+ | +--------+ |
| +-------------------+ | | | PTE63 | |
| | | : STE | | +-->+--------+ +0x0100 |
| | PGE2 | PME0 : STE | | | PTE64 | |
| | | : STE | | +--------+ |
| +-------------------+ | | PTE127 | |
| | | : STE | +------>+--------+ +0x0200 |
| | PGE3 | PME0 : STE | | PTE128 | |
| | | : STE | +--------+ |
| +-------------------+ | PTE191 | |
| +--------+ +0x0300 |
| |
| Each Page Directory (PGD) is 16KB (page size) in size and is divided into 64 entries (PGEs). Each |
| PGE contains one Page Mid Directory (PMD). |
| |
| Each PMD is 256 bytes in size and contains a single entry (PME). Each PME holds 64 FR451 MMU |
| segment table entries of 4 bytes apiece. Each PME "points to" a page table. In practice, each STE |
| points to a subset of the page table, the first to PT+0x0000, the second to PT+0x0100, the third to |
| PT+0x200, and so on. |
| |
| Each PGE and PME covers 64MB of the total virtual address space. |
| |
| Each Page Table (PTD) is 16KB (page size) in size, and is divided into 4096 entries (PTEs). Each |
| entry can point to one 16KB page. In practice, each Linux page table is subdivided into 64 FR451 |
| MMU page tables. But they are all grouped together to make management easier, in particular rmap |
| support is then trivial. |
| |
| Grouping page tables in this fashion makes PGE caching in SCR0/SCR1 more efficient because the |
| coverage of the cached item is greater. |
| |
| Page tables for the vmalloc area are allocated at boot time and shared between all mm_structs. |
| |
| |
| ================= |
| USER SPACE LAYOUT |
| ================= |
| |
| For MMU capable Linux, the regions userspace code are allowed to access are kept entirely separate |
| from those dedicated to the kernel: |
| |
| VIRTUAL ADDRESS SIZE PURPOSE |
| ================= ===== =================================== |
| 00000000-00003fff 4KB NULL pointer access trap |
| 00004000-01ffffff ~32MB lower mmap space (grows up) |
| 02000000-021fffff 2MB Stack space (grows down from top) |
| 02200000-nnnnnnnn Executable mapping |
| nnnnnnnn- brk space (grows up) |
| -bfffffff upper mmap space (grows down) |
| |
| This is so arranged so as to make best use of the 16KB page tables and the way in which PGEs/PMEs |
| are cached by the TLB handler. The lower mmap space is filled first, and then the upper mmap space |
| is filled. |
| |
| |
| =============================== |
| GDB-STUB MMU DEBUGGING SERVICES |
| =============================== |
| |
| The gdb-stub included in this kernel provides a number of services to aid in the debugging of MMU |
| related kernel services: |
| |
| (*) Every time the kernel stops, certain state information is dumped into __debug_mmu. This |
| variable is defined in arch/frv/kernel/gdb-stub.c. Note that the gdbinit file in this |
| directory has some useful macros for dealing with this. |
| |
| (*) __debug_mmu.tlb[] |
| |
| This receives the current TLB contents. This can be viewed with the _tlb GDB macro: |
| |
| (gdb) _tlb |
| tlb[0x00]: 01000005 00718203 01000002 00718203 |
| tlb[0x01]: 01004002 006d4201 01004005 006d4203 |
| tlb[0x02]: 01008002 006d0201 01008006 00004200 |
| tlb[0x03]: 0100c006 007f4202 0100c002 0064c202 |
| tlb[0x04]: 01110005 00774201 01110002 00774201 |
| tlb[0x05]: 01114005 00770201 01114002 00770201 |
| tlb[0x06]: 01118002 0076c201 01118005 0076c201 |
| ... |
| tlb[0x3d]: 010f4002 00790200 001f4002 0054ca02 |
| tlb[0x3e]: 010f8005 0078c201 010f8002 0078c201 |
| tlb[0x3f]: 001fc002 0056ca01 001fc005 00538a01 |
| |
| (*) __debug_mmu.iamr[] |
| (*) __debug_mmu.damr[] |
| |
| These receive the current IAMR and DAMR contents. These can be viewed with the _amr |
| GDB macro: |
| |
| (gdb) _amr |
| AMRx DAMR IAMR |
| ==== ===================== ===================== |
| amr0 : L:c0000000 P:00000cb9 : L:c0000000 P:000004b9 |
| amr1 : L:01070005 P:006f9203 : L:0102c005 P:006a1201 |
| amr2 : L:d8d00000 P:00000000 : L:d8d00000 P:00000000 |
| amr3 : L:d8d04000 P:00534c0d : L:00000000 P:00000000 |
| amr4 : L:d8d08000 P:00554c0d : L:00000000 P:00000000 |
| amr5 : L:d8d0c000 P:00554c0d : L:00000000 P:00000000 |
| amr6 : L:d8d10000 P:00000000 : L:00000000 P:00000000 |
| amr7 : L:d8d14000 P:00000000 : L:00000000 P:00000000 |
| amr8 : L:d8d18000 P:00000000 |
| amr9 : L:d8d1c000 P:00000000 |
| amr10: L:d8d20000 P:00000000 |
| amr11: L:e0000000 P:e0000ccd |
| |
| (*) The current task's page directory is bound to DAMR3. |
| |
| This can be viewed with the _pgd GDB macro: |
| |
| (gdb) _pgd |
| $3 = {{pge = {{ste = {0x554001, 0x554101, 0x554201, 0x554301, 0x554401, |
| 0x554501, 0x554601, 0x554701, 0x554801, 0x554901, 0x554a01, |
| 0x554b01, 0x554c01, 0x554d01, 0x554e01, 0x554f01, 0x555001, |
| 0x555101, 0x555201, 0x555301, 0x555401, 0x555501, 0x555601, |
| 0x555701, 0x555801, 0x555901, 0x555a01, 0x555b01, 0x555c01, |
| 0x555d01, 0x555e01, 0x555f01, 0x556001, 0x556101, 0x556201, |
| 0x556301, 0x556401, 0x556501, 0x556601, 0x556701, 0x556801, |
| 0x556901, 0x556a01, 0x556b01, 0x556c01, 0x556d01, 0x556e01, |
| 0x556f01, 0x557001, 0x557101, 0x557201, 0x557301, 0x557401, |
| 0x557501, 0x557601, 0x557701, 0x557801, 0x557901, 0x557a01, |
| 0x557b01, 0x557c01, 0x557d01, 0x557e01, 0x557f01}}}}, {pge = {{ |
| ste = {0x0 <repeats 64 times>}}}} <repeats 51 times>, {pge = {{ste = { |
| 0x248001, 0x248101, 0x248201, 0x248301, 0x248401, 0x248501, |
| 0x248601, 0x248701, 0x248801, 0x248901, 0x248a01, 0x248b01, |
| 0x248c01, 0x248d01, 0x248e01, 0x248f01, 0x249001, 0x249101, |
| 0x249201, 0x249301, 0x249401, 0x249501, 0x249601, 0x249701, |
| 0x249801, 0x249901, 0x249a01, 0x249b01, 0x249c01, 0x249d01, |
| 0x249e01, 0x249f01, 0x24a001, 0x24a101, 0x24a201, 0x24a301, |
| 0x24a401, 0x24a501, 0x24a601, 0x24a701, 0x24a801, 0x24a901, |
| 0x24aa01, 0x24ab01, 0x24ac01, 0x24ad01, 0x24ae01, 0x24af01, |
| 0x24b001, 0x24b101, 0x24b201, 0x24b301, 0x24b401, 0x24b501, |
| 0x24b601, 0x24b701, 0x24b801, 0x24b901, 0x24ba01, 0x24bb01, |
| 0x24bc01, 0x24bd01, 0x24be01, 0x24bf01}}}}, {pge = {{ste = { |
| 0x0 <repeats 64 times>}}}} <repeats 11 times>} |
| |
| (*) The PTD last used by the instruction TLB miss handler is attached to DAMR4. |
| (*) The PTD last used by the data TLB miss handler is attached to DAMR5. |
| |
| These can be viewed with the _ptd_i and _ptd_d GDB macros: |
| |
| (gdb) _ptd_d |
| $5 = {{pte = 0x0} <repeats 127 times>, {pte = 0x539b01}, { |
| pte = 0x0} <repeats 896 times>, {pte = 0x719303}, {pte = 0x6d5303}, { |
| pte = 0x0}, {pte = 0x0}, {pte = 0x0}, {pte = 0x0}, {pte = 0x0}, { |
| pte = 0x0}, {pte = 0x0}, {pte = 0x0}, {pte = 0x0}, {pte = 0x6a1303}, { |
| pte = 0x0} <repeats 12 times>, {pte = 0x709303}, {pte = 0x0}, {pte = 0x0}, |
| {pte = 0x6fd303}, {pte = 0x6f9303}, {pte = 0x6f5303}, {pte = 0x0}, { |
| pte = 0x6ed303}, {pte = 0x531b01}, {pte = 0x50db01}, { |
| pte = 0x0} <repeats 13 times>, {pte = 0x5303}, {pte = 0x7f5303}, { |
| pte = 0x509b01}, {pte = 0x505b01}, {pte = 0x7c9303}, {pte = 0x7b9303}, { |
| pte = 0x7b5303}, {pte = 0x7b1303}, {pte = 0x7ad303}, {pte = 0x0}, { |
| pte = 0x0}, {pte = 0x7a1303}, {pte = 0x0}, {pte = 0x795303}, {pte = 0x0}, { |
| pte = 0x78d303}, {pte = 0x0}, {pte = 0x0}, {pte = 0x0}, {pte = 0x0}, { |
| pte = 0x0}, {pte = 0x775303}, {pte = 0x771303}, {pte = 0x76d303}, { |
| pte = 0x0}, {pte = 0x765303}, {pte = 0x7c5303}, {pte = 0x501b01}, { |
| pte = 0x4f1b01}, {pte = 0x4edb01}, {pte = 0x0}, {pte = 0x4f9b01}, { |
| pte = 0x4fdb01}, {pte = 0x0} <repeats 2992 times>} |