sv39分页:虚拟地址只用了39位,所以才有这个名字

问题一: PTE的格式怎么样? 不同的模式格式都是一样的吗?
问题二: MMU需要什么样的数据,怎么样提前准备呢?
问题三: 怎么配置一个虚拟地址到物理地址到映射呢?
问题四: 内存的场景的位操作是怎么样的呢?
问题五: cpu怎么知道页的大小呢?

在RISC-V架构中,无论是Sv32、Sv39还是Sv48模式,页表条目(PTE)的格式都是固定的,都是64位。这种设计提供了一致性和灵活性,使得操作系统和硬件可以更容易地管理和转换地址。

截屏2024-07-07 11.44.20.png


知道一个地址怎么设置,就能知道一堆地址怎么设置。这个过程不能剩下!!!

我们需要设置一个页表条目,将虚拟地址 0x0000003F_FFFF_FFFF 映射到物理地址 0x12345000。假设我们要设置的页表条目在第三级页表中。

#include <stdint.h>

#define PAGE_SIZE_4KB  4096
#define PAGE_SIZE_2MB  (2 * 1024 * 1024)
#define PAGE_SIZE_1GB  (1024 * 1024 * 1024)

typedef uint64_t pte_t;

#define PTE_VALID      0x001
#define PTE_READ       0x002
#define PTE_WRITE      0x004
#define PTE_EXECUTE    0x008
#define PTE_USER       0x010
#define PTE_GLOBAL     0x020
#define PTE_ACCESSED   0x040
#define PTE_DIRTY      0x080
#define PTE_PAGE_SIZE  0x100 // 示例标志位,用于指示大页

void set_pte(pte_t *pte, uint64_t pa, uint64_t flags) {
    //以物理地址的低 12 位是页内偏移,不需要存储在 PTE 中。
    // PTE 的物理页号(PPN)字段从第 10 位开始,因此需要将物理页号对齐到 PTE 的正确位置。
    *pte = (pa >> 12) << 10 | flags;
}

int main() {
   // 假设页表的基地址
    pte_t pgd[512] __attribute__((aligned(PAGE_SIZE_4KB)));
    pte_t pmd[512] __attribute__((aligned(PAGE_SIZE_4KB)));
    pte_t pte[512] __attribute__((aligned(PAGE_SIZE_4KB)));

   // 虚拟地址和物理地址
    uint64_t va = 0x0000003F_FFFF_FFFF;
    uint64_t pa = 0x12345000;

     // 页表条目索引
     //0x1FF 是一个掩码,二进制表示为 111111111(即 9 个 1)。
    uint64_t pgd_idx = (va >> 30) & 0x1FF;
    uint64_t pmd_idx = (va >> 21) & 0x1FF;
    uint64_t pte_idx = (va >> 12) & 0x1FF;

    // 设置第三级页表条目(PTE)
    set_pte(&pte[pte_idx], pa, PTE_VALID | PTE_READ | PTE_WRITE | PTE_EXECUTE | PTE_USER);

    // 设置第二级页表条目(PMD),使其指向第三级页表
    set_pte(&pmd[pmd_idx], (uint64_t)pte, PTE_VALID);

    // 设置第一级页表条目(PGD),使其指向第二级页表
    set_pte(&pgd[pgd_idx], (uint64_t)pmd, PTE_VALID);

    return 0;
}

截屏2024-07-07 11.48.42.png


cpu 怎么知道是那个2MB大页,还是!1GB的大页,或者标准页4KB?

  1. 检查页表条目的有效性:
    首先检查页表条目的有效标志(V位),确保该条目是有效的。
  2. 检查页表条目的权限位:
    如果页表条目指向下一级页表,那么它的读(R)、写(W)和执行(X)权限位都应该为0。
    如果页表条目直接指向物理页(即叶子页),那么它至少会有一个权限位(R、W或X)被设置。
+-----------+-----------+-----------+-----------------+
| VPN[2]    | VPN[1]    | VPN[0]    | 页内偏移        |
+-----------+-----------+-----------+-----------------+
| 38-30     | 29-21     | 20-12     | 11-0            |
+-----------+-----------+-----------+-----------------+

void check_page_size(pte_t *pgd, uint64_t va) {
    uint64_t vpn2 = (va >> 30) & 0x1FF;
    uint64_t vpn1 = (va >> 21) & 0x1FF;
    uint64_t vpn0 = (va >> 12) & 0x1FF;

    pte_t pte = pgd[vpn2];
    if (!(pte & PTE_VALID)) {
        printf("Invalid PTE\n");
        return;
    }

    // 判断是否是非叶子页
    if (!(pte & (PTE_READ | PTE_WRITE | PTE_EXECUTE))) {
        pte_t *pmd = (pte_t *)((pte >> 10) << 12);
        pte = pmd[vpn1];
        if (!(pte & PTE_VALID)) {
            printf("Invalid PTE\n");
            return;
        }

        // 判断是否是非叶子页
        if (!(pte & (PTE_READ | PTE_WRITE | PTE_EXECUTE))) {
            pte_t *pte_table = (pte_t *)((pte >> 10) << 12);
            pte = pte_table[vpn0];
            if (!(pte & PTE_VALID)) {
                printf("Invalid PTE\n");
                return;
            }

            printf("4KB page\n");
        } else {
            printf("2MB page\n");
        }
    } else {
        printf("1GB page\n");
    }
}

putao
5 声望0 粉丝

推动世界向前发展,改善民生。