task4 finished

This commit is contained in:
2025-05-29 11:15:51 +08:00
parent f0aaffb0b6
commit 8fb0212778
2 changed files with 180 additions and 25 deletions

153
answers-pgtbl.txt Normal file
View File

@ -0,0 +1,153 @@
### 背景信息
- **页面表结构**
- 页面大小(`PGSIZE`):通常为 4KB4096 字节)。
- 最大虚拟地址(`MAXVA`):在 Sv39 模式下为 2^39512GB
- 页面表条目PTE包含物理地址PA、权限位读/写/执行等以及有效位Valid bit
- 三级页面表PML4顶级L2中间级L1最低级每个页面表包含 512 条目2^9
- 虚拟地址VA39 位,分为 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 的条目以及其下级页面表的最后几个条目509511
- 对应虚拟地址接近 `MAXVA``0x3fffffd` 到 `0x3ffffff`)。
- 输出格式:
- 每行表示一个页面表条目,格式为:
```
[索引]: pte [PTE值] pa [物理地址] [va 虚拟地址 flags 权限]
```
- 缩进(`..`表示页面表层级顶级无缩进、L2`..`、L1`.. ..`)。
- 仅 L1 页面表条目包含虚拟地址(`va`)和权限标志(`flags`)。
#### 2. **页面表条目解析**
页面表条目PTE格式RISC-V Sv39
- **PTE 结构**64 位,包含:
- 物理页面号PPN44 位(高 44 位,右移 10 位得到物理页面地址)。
- 权限位VValid有效、RRead、WWrite、XExecute执行、UUser用户态可访问
- 其他标志GGlobal、AAccessed、DDirty等。
- **物理地址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`,表示 ValidV=1
- **L2 页面表(索引 0**
- `..0: pte 0x0000000021fd2001 pa 0x0000000087f48000`
- PTE 值:`0x21fd2001`。
- 物理地址:`0x87f48000`L1 页面表地址)。
- 标志ValidV=1
- **L1 页面表(索引 03**
- `.. ..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 页面表地址)。
- 标志ValidV=1
- **L2 页面表(索引 511**
- `..511: pte 0x0000000021fd2c01 pa 0x0000000087f4b000`
- PTE 值:`0x21fd2c01`。
- 物理地址:`0x87f4b000`L1 页面表地址)。
- 标志ValidV=1
- **L1 页面表(索引 509511**
- `.. ..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 个页面**
- 输出显示索引 509511虚拟地址 `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 个页面509511可能是因为只有这些页面有有效映射。
- **缺失的 `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`,可能是设备寄存器或内核代码的固定映射。

View File

@ -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;i<num;i++){
uint64 query_addr = addr + i * PGSIZE ;
pte_t * pte=walk(p->pagetable, query_addr, 0);
if(*pte&PTE_A)
{
abits=abits|(1<<i);
*pte=(*pte)&(~PTE_A);
}
}
if (copyout(p->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;
}