Finer Granularity Mapping

Store page information in .data.pgd

在 Kernel 最尾段留一塊區域除存 page entry 資訊

src/linker.ld

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
  ... // skip

  .bss ALIGN(16) (NOLOAD) :
  {
    __bss_start = .;

    *(.bss)

    __bss_end = .;
  }

  . = ALIGN(0x1000);
  pg_dir = .;
  .data.pgd :
  {
    . += (2 * (1 << 12));
  }
  . = ALIGN(0x1000);

src/start.S

注意一開始還是用 physical address

 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
el1_start:
    ...

    // create page table
    bl      page_table_create

    ...

page_table_create:
    // omit first 16 bit (using physical address)
    ldr     x0, =pg_dir
    lsl     x0, x0, #16
    lsr     x0, x0, #16
    add     x1, x0, #PAGE_SIZE

    ldr     x2, =PGD_ATTR
    orr     x2, x1, x2 // PGD value
    str     x2, [x0]

    ldr     x2, =PUD1_VALUE // 1st 1GB mapped by the 1st entry of PUD
    str     x2, [x1]

    ldr     x2, =PUD2_VALUE // 2nd 1GB mapped by the 2nd entry of PUD
    str     x2, [x1, #8]

    msr     ttbr0_el1, x0 // load PGD to the buttom translation based register.
    msr     ttbr1_el1, x0 // load PGD to the upper translation based register.
    
    ret

4KB Granularity

將除了 MMIO 區域的記憶體設定成 normal memory (4KB * 512 * 512 = 1GB),MMIO 設定成 device memory (1GB)

Compiler 有時後會生成 unaligned access 的 code,設定成 device memory 會在 unaligned access 觸發 exception (alignment fault)

  • PGD * 1
  • PUD * 1
  • PMD * 1
  • PTE * 512

因此每個 page 若以 4KB 的粒度切分,需要預留 515 個 page 的空間存放 page entry

Page Table Layout

src/linker.ld

預留 515 個 page

1
2
3
4
5
6
  ...
  .data.pgd :
  {
    . += (515 * (1 << 12)); /* (PGD * 1) + (PUD * 1) + (PMD * 1) + (PTE * 512) */
  }
  ...

src/mmu.h

設定 Normal Memory 與 Device Memory 的 Attribute

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Page Descriptor

#define PD_TABLE                0b11
#define PD_BLOCK                0b01
#define PD_PAGE                 0b11
#define PD_ACCESS               (1 << 10)

#define PGD0_ATTR               PD_TABLE // Lower attributes is ignored
#define PUD0_ATTR               PD_TABLE // Lower attributes is ignored
#define PUD1_ATTR               (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK)
#define PMD0_ATTR               PD_TABLE // Lower attributes is ignored
#define PTE_MMIO_ATTR           (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_PAGE)
#define PTE_RAM_ATTR            (PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE)

src/start.S

設定 Page Table

 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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
page_table_create:
    /*
     * Each page table base address:
     *  x0: PGD (1 page, 1 entry)
     *  x1: PUD (1 page, 2 entry)
     *  x2: PMD (1 page, 512 entry)
     *  x3: PTE (512 page, each with 512 entry)
     */
    ldr     x0, =pg_dir
    lsl     x0, x0, #16  // omit first 16 bit (using physical address)
    lsr     x0, x0, #16
    add     x1, x0, #PAGE_SIZE
    add     x2, x1, #PAGE_SIZE
    add     x3, x2, #PAGE_SIZE

    // setup PGD
    ldr     x4, =PGD0_ATTR
    orr     x4, x1, x4 // PUD physical address
    str     x4, [x0]

    // setup PUD1
    ldr     x4, =PUD0_ATTR
    orr     x4, x2, x4 // PMD physical address
    str     x4, [x1]

    // setup PUD2 (1GB section start from 0x40000000)
    ldr     x4, =PUD1_ATTR
    mov     x5, 0x40000000
    orr     x4, x5, x4
    str     x4, [x1, #8]

    // setup PMD (512 entry in 1 page)
    mov     x4, x3 // point to current PTE address
    mov     x5, xzr // i = 0
    mov     x6, #512
1:
    ldr     x7, =PMD0_ATTR
    orr     x7, x4, x7 // PTE physical address
    str     x7, [x2, x5, lsl #3] // (i * 8)
    add     x5, x5, #1
    add     x4, x4, #PAGE_SIZE
    cmp     x5, x6
    b.ls    1b

    // setup normal PTE (512 * 512 - 4096 = 258048 entry)
    mov     x4, xzr // physical address
    mov     x5, xzr // i = 0
    mov     x6, #258048
2:
    ldr     x7, =PTE_RAM_ATTR
    orr     x7, x4, x7
    str     x7, [x3, x5, lsl #3] // (i * 8)
    add     x5, x5, #1
    add     x4, x4, #PAGE_SIZE
    cmp     x5, x6
    b.ls    2b

    // setup device PTE (16MB = 4096 entry)
    add     x6, x6, #4096 // 262144
3:
    ldr     x7, =PTE_MMIO_ATTR
    orr     x7, x4, x7
    str     x7, [x3, x5, lsl #3] // (i * 8)
    add     x5, x5, #1
    add     x4, x4, #PAGE_SIZE
    cmp     x5, x6
    b.ls    3b

    msr     ttbr0_el1, x0 // load PGD to the buttom translation based register.
    msr     ttbr1_el1, x0 // load PGD to the upper translation based register.
    
    ret

External Resources

AArch64 memory model - Normal memory

AArch64 memory model - Device memory

comments powered by Disqus