博客 / 詳情

返回

risc-v--sv39彙編實現

在 Sv39 模式下,虛擬地址是 39 位,分為三級頁表來管理:

第一級頁表(頁目錄):負責最高的 9 位虛擬地址。
第二級頁表(頁中間目錄):負責中間的 9 位虛擬地址。
第三級頁表(頁表):負責最低的 9 位虛擬地址。

9 位虛擬地址可以表示2的9次方=512個條目。
512條目×8字節/條目=4096字節=4KB

假設我們有一個頁表,包含多個條目,每個條目佔用 8 字節:
索引
計算偏移量
假設我們要訪問頁表中的第 5 個條目(Entry 5),它的索引是 5。為了計算這個條目在頁表中的實際地址,我們需要將索引乘以每個條目的大小(8 字節)。
索引:5
每個條目大小:8 字節
偏移量:5 * 8 = 40(十六進制是 0x28)
左移3位:5 << 3 = 5 2^3 = 5 8 = 40
最後,我們將計算出的偏移量加到頁表基地址上,得到實際的內存地址:
頁表基地址:0x80000000
偏移量:0x28
實際地址:0x80000000 + 0x28 = 0x80000028


.section .text
.global _start

# 程序入口
_start:
    # 初始化棧指針
    la sp, stack_top

    # 調用內存映射函數
    la a0, page_table_base    # 頁表基地址
    li a1, 0x80000000         # 物理地址起始
    li a2, 0x80000000         # 虛擬地址起始
    li a3, 0x80400000         # 虛擬地址結束(4MB)
    li a4, 0xF                # 保護標誌 (RWX)
    call map_identity

    # 啓用 MMU
    la a0, page_table_base
    call enable_mmu

    # 無限循環,防止程序退出
1:  j 1b

# 棧區定義
.section .bss
.balign 16
stack:
    .space 4096 * 4
stack_top:

# 頁表定義
.section .data
.balign 4096
page_table_base:
    .space 4096 * 3  # 頁目錄、頁中間目錄和頁表

# 函數:物理內存到虛擬內存的恆等映射
map_identity:
    # 保存寄存器
    addi sp, sp, -16
    sd ra, 8(sp)
    sd t0, 0(sp)

    # 初始化頁表基地址
    la t0, page_table_base

1:  # 循環開始
    # 計算虛擬地址的頁目錄索引
    srli t1, a2, 30                # 取高9位作為頁目錄索引
    andi t1, t1, 0x1FF             # 保留低9位

    # 計算頁中間目錄索引
    srli t2, a2, 21                # 取高9位作為頁中間目錄索引
    andi t2, t2, 0x1FF             # 保留低9位

    # 計算頁表索引
    srli t3, a2, 12                # 取高9位作為頁表索引
    andi t3, t3, 0x1FF             # 保留低9位

    # 計算頁表條目地址
    slli t1, t1, 3                 # 頁目錄索引左移3位
    add t1, t0, t1                 # 加上頁表基地址
    ld t1, 0(t1)                   # 讀取頁目錄條目

    # 檢查頁目錄條目是否存在
    andi t4, t1, 1                 # 檢查有效位
    beqz t4, create_pmd            # 如果不存在,創建頁中間目錄

    # 計算頁中間目錄地址
    slli t2, t2, 3                 # 頁中間目錄索引左移3位
    add t2, t1, t2                 # 加上頁目錄基地址
    ld t2, 0(t2)                   # 讀取頁中間目錄條目

    # 檢查頁中間目錄條目是否存在
    andi t4, t2, 1                 # 檢查有效位
    beqz t4, create_pte            # 如果不存在,創建頁表

    # 計算頁表地址
    slli t3, t3, 3                 # 頁表索引左移3位
    add t3, t2, t3                 # 加上頁中間目錄基地址
    ld t3, 0(t3)                   # 讀取頁表條目

    # 設置頁表條目
    or t3, a1, a4                  # 將物理地址和保護標誌合併
    sd t3, 0(t3)                   # 寫入頁表條目

    # 更新地址
    addi a2, a2, 0x1000            # 虛擬地址加上頁大小
    addi a1, a1, 0x1000            # 物理地址加上頁大小
    bltu a2, a3, 1b                # 如果虛擬地址小於結束地址,繼續循環

    # 恢復寄存器並返回
    ld ra, 8(sp)
    ld t0, 0(sp)
    addi sp, sp, 16
    ret

# 到此時,t0/t1/t2/t3 都使用了。 
create_pmd:
    # 創建頁中間目錄
    li t4, 0x1000                  # 分配一頁內存
    slli t4, t4, 12                # 左移12位,得到物理頁號
    or t4, t4, 1                   # 設置有效位
    sd t4, 0(t1)                   # 寫入頁目錄條目
    j 1b                           # 返回循環

create_pte:
    # 創建頁表
    li t4, 0x1000                  # 分配一頁內存
    slli t4, t4, 12                # 左移12位,得到物理頁號
    or t4, t4, 1                   # 設置有效位
    sd t4, 0(t2)                   # 寫入頁中間目錄條目
    j 1b                           # 返回循環

# 函數:啓用 MMU
enable_mmu:
    # 設置 satp 寄存器
    srli a2, a0, 12                # 將頁表基地址右移12位
    li t0, 8                       # Sv39 模式
    slli t0, t0, 60                # 左移60位,放置到 MODE 字段
    or a2, a2, t0                  # 合併 MODE 和 PPN
    csrw satp, a2                  # 寫入 satp 寄存器
    sfence.vma                     # 刷新 TLB
    ret
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.