Lab5: Identity Paging

Goals of this lab

  • Understand ARMv8-A virtual memory system architecture.
  • Understand how to design paging bookkeeping.
  • Understand how to design multitasking with virtual memory.
  • Understand how user programs loaded.
  • Understand how to prevent invalid memory access.
  • Understand how demand paging works.
  • Understand how copy-on-write works.

Settings

Source: Armv8-A Address Translation

TCR_EL1, Translation Control Register(EL1)

IPS

maximum output address size

  • 000=32 bits
  • 101=48 bits

TG0/TG1

the smallest block of memory that can be independently mapped in the translation tables.

  • 其實就是 page 大小
  • 00=4KB, 01=16KB, 11=64KB

T0SZ

The size offset of the memory region addressed by TTBR0_EL1. The region size is 2(64-T1SZ) bytes.

T1SZ

The size offset of the memory region addressed by TTBR1_EL1. The region size is 2(64-T1SZ) bytes.

1
2
3
4
5
6
7
8
/* Translation Control Register (TCR) */
#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16))
#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30))
#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB)

// set up TCR
ldr x0, = TCR_CONFIG_DEFAULT
msr tcr_el1, x0

TTBRn_EL1, Translation Table Base Register 0 (EL1)

TTBR0_EL1TTBR1_EL1 分別對應高位和低位的 virtual address,例如

  • TTBR0_EL1 對應的記憶體範圍 0x00000000_00000000~`0x0000FFFF_FFFFFFFF 大小為2^48 bytes,T0SZ`=64-48=12
  • TTBR1_EL1 對應的記憶體範圍 0xFFFF0000_00000000~`0xFFFFFFFF_FFFFFFFF 大小為2^48 bytes,T1SZ`=64-48=12

MAIR_EL1, Memory Attribute Indirection Register (EL1)

MMU 對不同的 memory block 用不同屬性描述,不同屬性對應著不同行為。

deivce memory 的屬性不多,又附加上幾種特性:

  • Gathering
  • Re-ording
  • Early Write Acknowledgement

lab 使用到兩種 memory attribute

  • Device memory nGnRnE:
    • Peripheral access.
    • The most restricted memory access.
  • Normal memory without cache:
    • Normal RAM access.
    • Memory gathering, reordering, and speculative execution are possible but without cache.

Reference: arm64 memory 属性 Device-nGnRnE

1
2
3
4
5
6
7
8
9
10
11
12
/* Memory attribute indirection register (MAIR) */
#define MAIR_DEVICE_nGnRnE 0b00000000
#define MAIR_NORMAL_NOCACHE 0b01000100
#define MAIR_IDX_DEVICE_nGnRnE 0
#define MAIR_IDX_NORMAL_NOCACHE 1

// set up MAIR
ldr x0, =( \
(MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | \
(MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)) \
)
msr mair_el1, x0

Translation Virtual Address To A Physical Adress

礙於架構因素,ARMv8-A 並不支援 64-bit virtual address,bits [63:48] 必須一致。

virtual address 0x000…使用 TTBR0_EL10xFFF…使用 TTBR1_EL1T0SZ/T1SZ 限制 TTBR0_EL1/TTBR1_EL1 的範圍。

4KB granule

64KB granule

Example

  • 64KB granule
  • 42-bit virtual address
  • 48-bit physical address

  1. VA[64:42]=1→使用 TTBR1 指向的 page table,VA [64:42]=0→使用 TTBR0 指向的 page table
  2. L2 page table 包含 2^13=8192 page table entry,並透過 VA[41:29] 進行索引進行查找
  3. MMU 檢查 page table entry 正確性及權限
  4. 該 page table entry 指向下一級 page table (table descriptor),以 VA[28:16] 作為索引進行查找
  5. MMU 檢查 page table entry 正確性及權限
  6. 該 page table entry 指向下一級 page (page descriptor),VA[47:16] 作為 PA[47:16],VA[15:0] 作為 PA[15:0]
  7. 返回 PA[47:0]

Identity Paging

將 virtual address 映射到相同的 physical address 為 identity paging。

kernel/start.S

映射 4GB memory,使用 Two-level translation

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
// load exception_table to VBAR_EL1
ldr x0, =exception_table
msr VBAR_EL1, x0

// set up TCR
ldr x0, = TCR_CONFIG_DEFAULT
msr tcr_el1, x0

// set up MAIR
ldr x0, =( \
(MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | \
(MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)) \
)
msr mair_el1, x0

// identity paging
mov x0, 0 // PGD's page frame at 0x0
mov x1, 0x1000 // PUD's page frame at 0x1000

ldr x2, = BOOT_PGD_ATTR
orr x2, x1, x2 // combine the physical address of next level page with attribute.
str x2, [x0]

ldr x2, = BOOT_PUD_ATTR
mov x3, 0x00000000
orr x3, x2, x3
str x3, [x1] // 1st 1GB mapped by the 1st entry of PUD
mov x3, 0x40000000
orr x3, x2, x3
str x3, [x1, 8] // 2nd 1GB mapped by the 2nd entry of PUD

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

mrs x2, sctlr_el1
orr x2 , x2, 1
msr sctlr_el1, x2 // enable MMU, cache remains disabled

bl main

Map kernel to the upper address space

kernel/start.S

1
2
3
4
5
6
7
8
9
10
		ldr     x2, = BOOT_PUD_ATTR
mov x3, 0x00000000
orr x3, x2, x3
str x3, [x1] // 1st 1GB mapped by the 1st entry of PUD
mov x3, 0x40000000
orr x3, x2, x3
str x3, [x1, 8] // 2nd 1GB mapped by the 2nd entry of PUD

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

kernel/linker.ld

kernel 現在被映射到 0xFFFF000000000000 上方,因此必須對 linker.ld 進行修改,以讓 program counter 及 stack pointer 使用正確的值。

1
2
3
4
5
6
7
SECTIONS
{
- . = 0x80000;
+ . = 0xffff000000000000; // kernel space
+ . += 0x80000; // kernel load address
_kernel_start = . ;
PROVIDE(_code = .);

KERNEL_VIRT_BASE

連同使用記憶體位置的 marco 都需要加上 offset。

include/mm.h

1
#define KERNEL_VIRT_BASE 0xFFFF000000000000

include/base.h

1
2
3
4
#include <include/mm.h>

#define MMIO_BASE (KERNEL_VIRT_BASE | 0x3F000000)
#define LOCAL_PERIPHERAL_BASE (KERNEL_VIRT_BASE | 0x40000000)

Indirect Branch

啟用 mmu 後,得將 stack pointer 加上 offset。進到 main 前再使用 indirect branch 調整 program counter,adr 等 pc-relative 的指令才會使用到 virtual address。

kernel/start.S

1
2
3
4
5
6
7
8
+		// mov sp to virtual address
+ ldr x0, =KERNEL_VIRT_BASE
+ add sp, sp, x0

+ // indirect branch
+ ldr x0, =boot_rest
+ br x0
+ boot_rest:

Demo

因為尚未切一塊 page 給 user,執行 user task 時會進到 exception handler。