Skip to content

PageTableSize

Steve.Cha edited this page Nov 5, 2019 · 2 revisions

[HOME]

MMU Page Table Size 계산

PGD PUD PMD PTE 의 매크로를 계산 해보자

#define CONFIG_ARM64_VA_BITS        48
#define VA_BITS                     48      // (CONFIG_ARM64_VA_BITS)
#define MAX_USER_VA_BITS            48      // VA_BITS
#define CONFIG_PGTABLE_LEVELS       4
#define CONFIG_ARM64_PA_BITS        48
#define PHYS_MASK_SHIFT             48      // (CONFIG_ARM64_PA_BITS)


/* PAGE_SHIFT determines the page size */
/* CONT_SHIFT determines the number of pages which can be tracked together  */
#define CONFIG_ARM64_PAGE_SHIFT     12
#define CONFIG_ARM64_CONT_SHIFT     4
#define PAGE_SHIFT                  12                      // CONFIG_ARM64_PAGE_SHIFT
#define CONT_SHIFT                  4                       // CONFIG_ARM64_CONT_SHIFT
#define PAGE_SIZE                   0x1000                  // (_AC(1, UL) << PAGE_SHIFT)   <- (1 << 12) = 4096 = 4 KB
#define PAGE_MASK                   0xFFFFFFFF_FFFFF000     // (~(PAGE_SIZE-1))

#define CONT_SIZE                   0x10000                 // (_AC(1, UL) << (CONT_SHIFT + PAGE_SHIFT))   <- (1 << (4 + 12)) = 65536 = 64 KB
#define CONT_MASK                   0xFFFFFFFF_FFFF0000     // (~(CONT_SIZE-1))

#define SWAPPER_PGTABLE_LEVELS      3                       // (CONFIG_PGTABLE_LEVELS - 1)                          // (4-1)
#define IDMAP_PGTABLE_LEVELS        3                       // (ARM64_HW_PGTABLE_LEVELS(PHYS_MASK_SHIFT) - 1)       // (4-1)

/*
 * Number of page-table levels required to address 'va_bits' wide
 * address, without section mapping. We resolve the top (va_bits - PAGE_SHIFT)
 * bits with (PAGE_SHIFT - 3) bits at each page table level. Hence:
 *
 *  levels = DIV_ROUND_UP((va_bits - PAGE_SHIFT), (PAGE_SHIFT - 3))
 *
 * where DIV_ROUND_UP(n, d) => (((n) + (d) - 1) / (d))
 *
 * We cannot include linux/kernel.h which defines DIV_ROUND_UP here
 * due to build issues. So we open code DIV_ROUND_UP here:
 *
 *	((((va_bits) - PAGE_SHIFT) + (PAGE_SHIFT - 3) - 1) / (PAGE_SHIFT - 3))
 *
 * which gets simplified as :
 */
#define ARM64_HW_PGTABLE_LEVELS(va_bits) (((va_bits) - 4) / (PAGE_SHIFT - 3))

/*
 * Size mapped by an entry at level n ( 0 <= n <= 3)
 * We map (PAGE_SHIFT - 3) at all translation levels and PAGE_SHIFT bits
 * in the final page. The maximum number of translation levels supported by
 * the architecture is 4. Hence, starting at at level n, we have further
 * ((4 - n) - 1) levels of translation excluding the offset within the page.
 * So, the total number of bits mapped by an entry at level n is :
 *
 *  ((4 - n) - 1) * (PAGE_SHIFT - 3) + PAGE_SHIFT
 *  ((4 - n) - 1) * (12         - 3) + 12
 *
 * Rearranging it a bit we get :
 *   (4 - n) * (PAGE_SHIFT - 3) + 3
 *   (4 - n) * (12         - 3) + 3
 */
#define ARM64_HW_PGTABLE_LEVEL_SHIFT(n) ((PAGE_SHIFT - 3) * (4 - (n)) + 3)  

#define PTRS_PER_PTE                    (1 << (PAGE_SHIFT - 3))


/*
 * PMD_SHIFT determines the size a level 2 page table entry can map.
 */
#if CONFIG_PGTABLE_LEVELS > 2
#define PMD_SHIFT               21                      // ARM64_HW_PGTABLE_LEVEL_SHIFT(2) // <- ((9 * (4 - 2)) + 3)
#define PMD_SIZE                0x200000                // (_AC(1, UL) << PMD_SHIFT)
#define PMD_MASK                0xFFFFFFFF_FFE00000     // (~(PMD_SIZE-1))
#define PTRS_PER_PMD            512                     // PTRS_PER_PTE
#endif

/*
 * PUD_SHIFT determines the size a level 1 page table entry can map.
 */
#if CONFIG_PGTABLE_LEVELS > 3
#define PUD_SHIFT               30                      // ARM64_HW_PGTABLE_LEVEL_SHIFT(1) // <- ((9 * (4 - 1)) + 3)
#define PUD_SIZE                0x40000000              // (_AC(1, UL) << PUD_SHIFT)
#define PUD_MASK                0xFFFFFFFF_C0000000     // (~(PUD_SIZE-1))
#define PTRS_PER_PUD            512                     // PTRS_PER_PTE    // (1 << 12)
#endif

/*
 * PGDIR_SHIFT determines the size a top-level page table entry can map
 * (depending on the configuration, this level can be 0, 1 or 2).
 */
#define CONFIG_PGTABLE_LEVELS   4
#define PGDIR_SHIFT             39                      // ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - CONFIG_PGTABLE_LEVELS)  // <- ((9 * (4 - 0)) + 3)
#define PGDIR_SIZE              0x80_00000000           // (_AC(1, UL) << PGDIR_SHIFT)
#define PGDIR_MASK              0xFFFFFF80_00000000     // (~(PGDIR_SIZE-1))
#define PTRS_PER_PGD            512                     // (1 << (MAX_USER_VA_BITS - PGDIR_SHIFT)) // <- (1 << (48 - 39))

물리주소를 48 bit를 사용한다.

Level 0 Level 1 Level 2 Level 3 Offset
Name PGDIR PUD PMD PMD Offset
48 bits = 9 bits 9 bits 9 bits 9 bits 12 bits
start index 39 30 21 12 0
PGDIR_SHIFT PUD_SHIFT PMD_SHIFT PTE

변환테이블

MMU의 Page Table Size 계산 식은 아래와 같다.

#define EARLY_KASLR             (0)

#define SWAPPER_BLOCK_SHIFT     SECTION_SHIFT
#define SWAPPER_BLOCK_SIZE      SECTION_SIZE
#define SWAPPER_TABLE_SHIFT     PUD_SHIFT

#define EARLY_ENTRIES(vstart, vend, shift) (((vend) >> (shift)) \
                                        - ((vstart) >> (shift)) + 1 + EARLY_KASLR)

#define EARLY_PGDS(vstart, vend) (EARLY_ENTRIES(vstart, vend, PGDIR_SHIFT))
#define EARLY_PUDS(vstart, vend) (0)
#define EARLY_PMDS(vstart, vend) (EARLY_ENTRIES(vstart, vend, SWAPPER_TABLE_SHIFT))


#define EARLY_PAGES(vstart, vend) ( 1                   /* PGDIR page */                                \
                    + EARLY_PGDS((vstart), (vend))      /* each PGDIR needs a next level page table */  \
                    + EARLY_PUDS((vstart), (vend))      /* each PUD needs a next level page table */    \
                    + EARLY_PMDS((vstart), (vend)))     /* each PMD needs a next level page table */

--> 1. INIT_DIR 크기 계산
    start = ffff000010080000 = KIMAGE_VADDR + TEXT_OFFSET
   _etext = ffff000010ba0000
   _edata = ffff00001142ca00
    _end  = ffff0000114a0000
                      200000
    EARLY_PGDS  = 1 = (FFFFFFFF_FFFFFE00 - FFFFFFFF_FFFFFE00) + 1 + 0
    EARLY_PUDS  = 0
    EARLY_PMDS  = 1 = (FFFFFFFF_FFFC0000 - FFFFFFFF_FFFC0000) + 1 + 0
    EARLY_PAGES = 3 = 1 + 1 + 0 + 1 = 1 + EARLY_PGDS + EARLY_PUDS + EARLY_PMDS

#define INIT_DIR_SIZE       (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR + TEXT_OFFSET, _end))
                            (0x1000 * 3)
    init_pg_dir     = ffff00001149d000
    init_pg_end     = ffff0000114a0000
    sizeof(init_pg) = 3 PAGE = 0x3000 = ffff0000114a0000 - ffff00001149d000
    _end - start    = 5152 * 4096 = 0x1420000
                                       200000


#define IDMAP_DIR_SIZE      (IDMAP_PGTABLE_LEVELS * PAGE_SIZE)
                            (3 * 0x1000)

    idmap_pg_dir     = ffff000011116000
    tramp_pg_dir     = ffff000011119000
    sizeof(idmap_pg) = 3 PAGE = 0x3000

Clone this wiki locally