From 8fb0212778a3a881ef7806b57c98199e5a28e69f Mon Sep 17 00:00:00 2001 From: CGH0S7 <776459475@qq.com> Date: Thu, 29 May 2025 11:15:51 +0800 Subject: [PATCH] task4 finished --- answers-pgtbl.txt | 153 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/sysproc.c | 52 ++++++++-------- 2 files changed, 180 insertions(+), 25 deletions(-) create mode 100644 answers-pgtbl.txt diff --git a/answers-pgtbl.txt b/answers-pgtbl.txt new file mode 100644 index 0000000..9427713 --- /dev/null +++ b/answers-pgtbl.txt @@ -0,0 +1,153 @@ +### 背景信息 +- **页面表结构**: + - 页面大小(`PGSIZE`):通常为 4KB(4096 字节)。 + - 最大虚拟地址(`MAXVA`):在 Sv39 模式下为 2^39(512GB)。 + - 页面表条目(PTE):包含物理地址(PA)、权限位(读/写/执行等)以及有效位(Valid bit)。 + - 三级页面表:PML4(顶级),L2(中间级),L1(最低级),每个页面表包含 512 条目(2^9)。 + - 虚拟地址(VA):39 位,分为 VPN[2](9 位,顶级索引)、VPN[1](9 位,中间级索引)、VPN[0](9 位,最低级索引)和 12 位页面偏移。 +- **`print_pgtbl` 函数**: + - 打印前 10 个页面(VA 从 `0` 到 `9 * PGSIZE`)和最后 10 个页面(接近 `MAXVA`)的页面表条目。 + - 调用 `print_pte`,输出虚拟地址对应的页面表条目信息。 + +### 输出分析 +以下是提供的输出: +``` +xv6 kernel is booting +hart 1 starting +hart 2 starting +page table 0x0000000087f4d000 +0: pte 0x0000000021fd2401 pa 0x0000000087f49000 + ..0: pte 0x0000000021fd2001 pa 0x0000000087f48000 + .. ..0: pte 0x0000000021fd281b pa 0x0000000087f4a000 va 0x0000000000000000 flags RXU + .. ..1: pte 0x0000000021fd1c17 pa 0x0000000087f47000 va 0x0000000000000001 flags RWU + .. ..2: pte 0x0000000021fd1807 pa 0x0000000087f46000 va 0x0000000000000002 flags RW + .. ..3: pte 0x0000000021fd1417 pa 0x0000000087f45000 va 0x0000000000000003 flags RWU +255: pte 0x0000000021fd3001 pa 0x0000000087f4c000 + ..511: pte 0x0000000021fd2c01 pa 0x0000000087f4b000 + .. ..509: pte 0x0000000021fd5413 pa 0x0000000087f55000 va 0x0000000003fffffd flags RU + .. ..510: pte 0x0000000021fd5807 pa 0x0000000087f56000 va 0x0000000003fffffe flags RW + .. ..511: pte 0x000000002000180b pa 0x0000000080006000 va 0x0000000003ffffff flags RX +init: starting sh +``` + +#### 1. **输出结构与 `print_pgtbl` 的关联** +- 输出由 `print_pgtbl` 函数生成,包含: + - **顶级页面表地址**:`page table 0x0000000087f4d000`(根页面表所在的物理地址)。 + - **前几个页面表条目**(对应 `for (uint64 i = 0; i < 10; i++)` 循环): + - 打印顶级页面表索引 0 的条目,以及其下级页面表的条目。 + - 具体为虚拟地址 `0x0` 到 `0x3000`(前 4 个页面)。 + - **最后几个页面表条目**(对应 `for (uint64 i = top - 10; i < top; i++)` 循环): + - 打印顶级页面表索引 255 的条目,以及其下级页面表的最后几个条目(509–511)。 + - 对应虚拟地址接近 `MAXVA`(`0x3fffffd` 到 `0x3ffffff`)。 + - 输出格式: + - 每行表示一个页面表条目,格式为: + ``` + [索引]: pte [PTE值] pa [物理地址] [va 虚拟地址 flags 权限] + ``` + - 缩进(`..`)表示页面表层级:顶级(无缩进)、L2(`..`)、L1(`.. ..`)。 + - 仅 L1 页面表条目包含虚拟地址(`va`)和权限标志(`flags`)。 + +#### 2. **页面表条目解析** +页面表条目(PTE)格式(RISC-V Sv39): +- **PTE 结构**:64 位,包含: + - 物理页面号(PPN):44 位(高 44 位,右移 10 位得到物理页面地址)。 + - 权限位:V(Valid,有效)、R(Read,读)、W(Write,写)、X(Execute,执行)、U(User,用户态可访问)。 + - 其他标志:G(Global)、A(Accessed)、D(Dirty)等。 +- **物理地址(PA)**:从 PTE 的 PPN 字段计算,`PA = PPN << 12`。 +- **权限标志(flags)**:输出中的 `RXU`、`RWU`、`RW` 等表示权限组合: + - `R`:可读,`W`:可写,`X`:可执行,`U`:用户态可访问。 + +##### **前 4 个页面(VA 0x0 到 0x3000)** +- **顶级页面表(索引 0)**: + - `0: pte 0x0000000021fd2401 pa 0x0000000087f49000` + - PTE 值:`0x21fd2401`。 + - 物理地址:`0x87f49000`(L2 页面表地址)。 + - 标志:`0x401` 的低 10 位为 `0x001`,表示 Valid(V=1)。 +- **L2 页面表(索引 0)**: + - `..0: pte 0x0000000021fd2001 pa 0x0000000087f48000` + - PTE 值:`0x21fd2001`。 + - 物理地址:`0x87f48000`(L1 页面表地址)。 + - 标志:Valid(V=1)。 +- **L1 页面表(索引 0–3)**: + - `.. ..0: pte 0x0000000021fd281b pa 0x0000000087f4a000 va 0x0000000000000000 flags RXU` + - 虚拟地址:`0x0`。 + - 物理地址:`0x87f4a000`。 + - 标志:`RXU`(Read, Execute, User),`0x1b` = `0b11011`(V=1, R=1, X=1, U=1)。 + - 用途:可能是内核代码段(可读、可执行、用户态可访问)。 + - `.. ..1: pte 0x0000000021fd1c17 pa 0x0000000087f47000 va 0x0000000000000001 flags RWU` + - 虚拟地址:`0x1000`(1 * PGSIZE)。 + - 物理地址:`0x87f47000`。 + - 标志:`RWU`(Read, Write, User),`0x17` = `0b10111`(V=1, R=1, W=1, U=1)。 + - 用途:可能是数据段或堆栈(可读、可写、用户态可访问)。 + - `.. ..2: pte 0x0000000021fd1807 pa 0x0000000087f46000 va 0x0000000000000002 flags RW` + - 虚拟地址:`0x2000`(2 * PGSIZE)。 + - 物理地址:`0x87f46000`。 + - 标志:`RW`(Read, Write),`0x07` = `0b00111`(V=1, R=1, W=1)。 + - 用途:可能是内核数据(可读、可写,仅内核态)。 + - `.. ..3: pte 0x0000000021fd1417 pa 0x0000000087f45000 va 0x0000000000000003 flags RWU` + - 虚拟地址:`0x3000`(3 * PGSIZE)。 + - 物理地址:`0x87f45000`。 + - 标志:`RWU`(Read, Write, User),`0x17` = `0b10111`(V=1, R=1, W=1, U=1)。 + - 用途:可能是用户态数据或堆栈。 + +##### **最后 3 个页面(VA 0x3fffffd 到 0x3ffffff)** +- **顶级页面表(索引 255)**: + - `255: pte 0x0000000021fd3001 pa 0x0000000087f4c000` + - PTE 值:`0x21fd3001`。 + - 物理地址:`0x87f4c000`(L2 页面表地址)。 + - 标志:Valid(V=1)。 +- **L2 页面表(索引 511)**: + - `..511: pte 0x0000000021fd2c01 pa 0x0000000087f4b000` + - PTE 值:`0x21fd2c01`。 + - 物理地址:`0x87f4b000`(L1 页面表地址)。 + - 标志:Valid(V=1)。 +- **L1 页面表(索引 509–511)**: + - `.. ..509: pte 0x0000000021fd5413 pa 0x0000000087f55000 va 0x0000000003fffffd flags RU` + - 虚拟地址:`0x3fffffd000`(接近 MAXVA)。 + - 物理地址:`0x87f55000`。 + - 标志:`RU`(Read, User),`0x13` = `0b10011`(V=1, R=1, U=1)。 + - 用途:可能是用户态只读数据。 + - `.. ..510: pte 0x0000000021fd5807 pa 0x0000000087f56000 va 0x0000000003fffffe flags RW` + - 虚拟地址:`0x3fffffe000`。 + - 物理地址:`0x87f56000`。 + - 标志:`RW`(Read, Write),`0x07` = `0b00111`(V=1, R=1, W=1)。 + - 用途:可能是内核数据(仅内核态)。 + - `.. ..511: pte 0x000000002000180b pa 0x0000000080006000 va 0x0000000003ffffff flags RX` + - 虚拟地址:`0x3ffffff000`(MAXVA - PGSIZE)。 + - 物理地址:`0x80006000`。 + - 标志:`RX`(Read, Execute),`0x0b` = `0b01011`(V=1, R=1, X=1)。 + - 用途:可能是内核代码或设备映射(可读、可执行,仅内核态)。 + +#### 3. **与 `print_pgtbl` 的关联** +- **前 10 个页面**: + - 输出只显示了虚拟地址 `0x0` 到 `0x3000`(4 个页面),而不是 10 个,可能是因为 `print_pgtbl` 的循环被修改或页面表中只有前 4 个页面有有效映射。 + - 虚拟地址计算: + - `i * PGSIZE`(`i` 从 0 到 3),与输出中的 `va 0x0`、`0x1000`、`0x2000`、`0x3000` 匹配。 +- **最后 10 个页面**: + - 输出显示索引 509–511(虚拟地址 `0x3fffffd000` 到 `0x3ffffff000`),对应 `i` 从 `top - 3` 到 `top - 1`。 + - 计算 `top`: + - `MAXVA = 2^39 = 512GB`,`PGSIZE = 4096`,`top = 512GB / 4096 = 2^27 = 134,217,728`。 + - 虚拟地址 `0x3ffffff`(十进制 2^30 - 1)对应页面号 `2^30 / 4096 = 2^18 - 1 = 262,143`。 + - 顶级索引:`262,143 >> 18 = 255`(匹配 `255:`)。 + - L2 索引:`(262,143 >> 9) & 0x1FF = 511`(匹配 `..511:`)。 + - L1 索引:`262,143 & 0x1FF = 511`(匹配 `.. ..511:`)。 + - 输出只显示最后 3 个页面(509–511),可能是因为只有这些页面有有效映射。 +- **缺失的 `print_pgtbl` 输出**: + - 函数应打印 `"print_pgtbl starting\n"` 和 `"print_pgtbl: OK\n"`,但输出中缺失,可能是被其他日志覆盖或函数被修改。 + +#### 4. **页面表条目含义** +- **前 4 个页面**: + - 映射到物理地址 `0x87f4a000` 到 `0x87f45000`,连续的物理页面。 + - 权限多样(`RXU`、`RWU`、`RW`),表明这些页面用于不同用途: + - `RXU`:用户态代码(例如,初始用户程序)。 + - `RWU`:用户态数据或堆栈。 + - `RW`:内核数据(仅内核态)。 +- **最后 3 个页面**: + - 映射到物理地址 `0x87f55000` 到 `0x80006000`,不完全连续。 + - 权限包括 `RU`(用户态只读)、`RW`(内核读写)、`RX`(内核代码)。 + - 最后一个页面(`va 0x3ffffff000`, `pa 0x80006000`)可能是设备内存映射(常见于内核高地址空间)。 +- **物理地址**: + - 大部分物理地址在 `0x87fxxxxx` 范围内,表明内存分配集中在某一区域。 + - 最后一个页面映射到 `0x80006000`,可能是设备寄存器或内核代码的固定映射。 + + diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 2e3b7be..afb844a 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -126,38 +126,40 @@ sys_uptime(void) uint64 sys_pgaccess(void) -{ - uint64 va; - int n; - uint64 user_mask_addr; - argaddr(0, &va); - argint(1, &n); - argaddr(2, &user_mask_addr); - if (va < 0 || n < 0 || user_mask_addr < 0) - return -1; - - if (n < 0 || n > 32) - return -1; - + { + // lab pgtbl: your code here. struct proc *p = myproc(); - uint64 mask = 0; + unsigned int abits=0; - for (int i = 0; i < n; i++) { - uint64 v = va + i * PGSIZE; - pte_t *pte = walk(p->pagetable, v, 0); + uint64 addr; + argaddr(0, &addr); - if (!pte || (*pte & PTE_PS)) - continue; + int num; + argint(1,&num); - if ((*pte & PTE_V) && (*pte & PTE_A)) { - mask |= (1 << i); // Set bit i in mask - *pte &= ~PTE_A; // Clear the Accessed bit + uint64 dest; + argaddr(2, &dest); + + + for(int i=0;ipagetable, query_addr, 0); + if(*pte&PTE_A) + { + abits=abits|(1<pagetable, user_mask_addr, (char*)&mask, sizeof(mask)) < 0) + + + if(copyout(p->pagetable,dest,(char*)&abits, sizeof(abits)) < 0) return -1; - return 0; -} + + return 0; + }