-
Notifications
You must be signed in to change notification settings - Fork 6
PageTableSize
Steve.Cha edited this page Nov 5, 2019
·
2 revisions
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