Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
286 changes: 171 additions & 115 deletions all/03-3-lab2-spoc-discussion.md
Original file line number Diff line number Diff line change
@@ -1,199 +1,255 @@
# lec7\(lab2\) SPOC思考题
lec7(lab2) SPOC思考题

NOTICE

* 有"w4l1"标记的题是助教要提交到学堂在线上的。
* 有"w4l1"和"spoc"标记的题是要求拿清华学分的同学要在实体课上完成,并按时提交到学生对应的git repo上。
* 有"hard"标记的题有一定难度,鼓励实现。
* 有"easy"标记的题很容易实现,鼓励实现。
* 有"midd"标记的题是一般水平,鼓励实现。
- 有"w4l1"标记的题是助教要提交到学堂在线上的。
- 有"w4l1"和"spoc"标记的题是要求拿清华学分的同学要在实体课上完成,并按时提交到学生对应的git repo上。
- 有"hard"标记的题有一定难度,鼓励实现。
- 有"easy"标记的题很容易实现,鼓励实现。
- 有"midd"标记的题是一般水平,鼓励实现。

## 提前准备
提前准备

* 完成lec7\(lab2\)的视频学习和提交对应的在线练习
* git pull ucore\_os\_lab, v9\_cpu, os\_course\_spoc\_exercises  in github repos。这样可以在本机上完成课堂练习。
* 理解如何实现建立页表(主要自学和网上查找)
- 完成lec7(lab2)的视频学习和提交对应的在线练习
- git pull ucore_os_lab, v9_cpu, os_course_spoc_exercises  in github repos。这样可以在本机上完成课堂练习。
- 理解如何实现建立页表(主要自学和网上查找)

## 第七讲视频相关思考题
第七讲视频相关思考题

### 7.1 了解x86保护模式中的特权级
7.1 了解x86保护模式中的特权级

1. X86有几个特权级?
{%s%}
在保护模式下提供4个特权级,Ring 0表示最高特权级,Ring 3表示最低特权级。
{%ends%}
2. 不同特权级有什么区别?
{%s%}
不同特权级对硬件的控制权不同。特权级是CPU提供的一种通过硬件方式来处理不同级别进程权限的方式,具体权限由操作系统决定。在Linux中,内核态处于Ring0级,对软硬件由完全对控制权;用户态处于Ring 3级不能执行一些特殊指令,不能直接访问硬件和一些敏感的系统资源。
{%ends%}

### 7.2 了解特权级切换过程
7.2 了解特权级切换过程

1. 一条指令在执行时会有哪些可能的特权级判断?
{%s%}
访问门时,CPL<=DPL[门] && CPL>=DPL[段]
访问段时,MAX(CPL, RPL)<=DPL[段]
{%ends%}
2. 在什么情况下会出现特权级切换?
{%s%}
(1)访问数据段
(2)访问页表
(3)系统调用
(4)异常
(5)外围设备的中断
{%ends%}

### 7.3 了解段/页表
7.3 了解段/页表

1. 一条指令执行时最多会出现多少次地址转换?
{%s%}
三次,分别是:
(1)使用分段机制把程序的逻辑地址变换成处理器可寻址的内存空间(称为线性地址空间)中的地址;
(2)使用分页机制取得页目录地址和页表地址,获得BASE ADDRESS
(4)BASE ADDRESS,加上offset得到物理地址。
{%ends%}
2. 描述X86-32的MMU地址转换过程;
{%s%}
(1)根据段选择子SEGMENT REGISTER作为GDT或者LDT的INDEX,取出对应的GDT/LDT ENTRY;
(2)从GDT/LDT处取出BASE ADDRESS 和LIMIT,将要访问的地址首先进行ACCESS CHECK,是否超出SEGMENT的限制;
(3)将要访问的ADDRESS加上BASE ADDRESS,形成32bit的虚拟地址;
(4)取出页表的地址,并且使用page_index作为INDEX;
(5)从PTE中获得PAGE的真正物理地址的BASE ADDRESS。此BASE ADDRESS表名了物理地址的高20位.,加上虚拟地址的offset就是物理地址所在了。
{%ends%}

### 7.4 了解UCORE建立段/页表
7.4 了解UCORE建立段/页表

1. 分析MMU的使能过程;
{%s%}
建立页目录和页表后,对CR0的最高位(31bit)置1。
{%ends%}
2. 分析页表的建立过程;

## 个人思考题
{%s%}
(1)申请directory table的空间;
(2)清空页目录表的空间;
(3)建立0xC0000000-0xF8000000(va)到0x00000000-0x38000000(pa)的映射;
(4)建立0x00000000-0x00100000(va)到0x00000000-0x00100000(pa)的映射;
(5)通过CR3和CR0使能MMU;
(6)更新GDT;
(7)取消0x00000000-0x00100000的映射;
{%ends%}

个人思考题

---

x86保护模式中权限管理无处不在,下面哪些时候要检查访问权限\(\) \(w4l1\)
x86保护模式中权限管理无处不在,下面哪些时候要检查访问权限() (w4l1)

- [ ] 内存寻址过程中
- [ ] 代码跳转过程中
- [ ] 中断处理过程中
- [ ] ALU计算过程中

前三个需要。这里假定ALU完成计算所需数据都已经在CPU内部了。

* [x] 内存寻址过程中
* [x] 代码跳转过程中
* [x] 中断处理过程中
* [ ] ALU计算过程中
请描述ucore OS建立页机制的准备工作包括哪些步骤? (w4l1)

> 前三个需要。这里假定ALU完成计算所需数据都已经在CPU内部了。
{%s%}

请描述ucore OS建立页机制的准备工作包括哪些步骤? \(w4l1\)
ucore OS是基于80386 CPU实现的,所以CPU在进入保护模式后,就直接使能了段机制,并使得ucore OS需要在段机制的基础上建立页机制。首先ucore初始化GDT表,通过逻辑地址的高位段选择子查找GDT表中对应的段描述符到段基址,加上逻辑地址的低位offset得到线性地址(ucore中段式管理只起到了一个过渡作用,它将逻辑地址不加转换直接映射成线性地址)。在进入保护模式之前,通过BIOS中断调用得到系统物理内存的分布,这部分信息将在bootloader启动ucore后,由ucore的page_init函数来根据struct e820map的memmap(定义了起始地址为0x8000)来完成对整个机器中的物理内存的总体管理。确定好物理页所需的页目录表和页表的大小后,首先分配一个空闲物理页用于页目录表,然后建立物理地址和页目录项和页表项的一一映射,最后通过lcr3指令把页目录表的起始地址存入CR3寄存器中,通过lcr0指令把cr0中的CR0_PG标志位设置上,使能页机制。

```
+ 采分点:说明了ucore OS在让页机制正常工作的主要准备工作
- 答案没有涉及如下3点;(0分)
- 描述了对GDT的初始化,完成了段机制(1分)
- 除第二点外进一步描述了对物理内存的探测和空闲物理内存的管理。(2分)
- 除上述两点外,进一步描述了页表建立初始过程和设置CR0控寄存器某位来使能页(3分)
```
{%ends%}

* [x]
>
+ 采分点:说明了ucore OS在让页机制正常工作的主要准备工作
- 答案没有涉及如下3点;(0分)
- 描述了对GDT的初始化,完成了段机制(1分)
- 除第二点外进一步描述了对物理内存的探测和空闲物理内存的管理。(2分)
- 除上述两点外,进一步描述了页表建立初始过程和设置CR0控寄存器某位来使能页(3分)

---

## 小组思考题
小组思考题

---

(1)(spoc)请用lab1实验的基准代码(即没有修改的需要填空的源代码)来做如下实验: 执行`make qemu`,会得到一个输出结果,请给出合理的解释:为何qemu退出了?【提示】需要对qemu增加一些用于显示执行过程的参数,重点是分析其执行的指令和产生的中断或异常。 可试试"qemu-system-i386 -d help"
(1)(spoc)请用lab1实验的基准代码(即没有修改的需要填空的源代码)来做如下实验: 执行make qemu,会得到一个输出结果,请给出合理的解释:为何qemu退出了?【提示】需要对qemu增加一些用于显示执行过程的参数,重点是分析其执行的指令和产生的中断或异常。 可试试"qemu-system-i386 -d help"

{%s%}

在lab1的kern/debug/kdebug.c中,print_stackframe(void)函数没有实现。

{%ends%}

* [x]
>
(2)(spoc)假定你已经完成了lab1的实验,接下来是对lab1的中断处理的回顾:请把你的学号对37(十进制)取模,得到一个数x(x的范围是-1<x<37),然后在你的答案的基础上,修init.c中的kern_init函数,在大约36行处,即

(2)\(spoc\)假定你已经完成了lab1的实验,接下来是对lab1的中断处理的回顾:请把你的学号对37\(十进制\)取模,得到一个数x(x的范围是-1&lt;x&lt;37),然后在你的答案的基础上,修init.c中的kern\_init函数,在大约36行处,即
intr_enable(); // enable irq interrupt



```
intr_enable(); // enable irq interrupt
```
语句之后,加入如下语句(把x替换为你学号 mod 37得的值):

语句之后,加入如下语句\(把x替换为你学号 mod 37得的值\):
asm volatile ("int $x");

```
asm volatile ("int $x");
```
然后,请回答加入这条语句后,执行make qemu的输出结果与你没有加入这条语句后执行make qemu的输出结果的差异,并解释为什么有差异或没差异?

然后,请回答加入这条语句后,执行`make qemu`的输出结果与你没有加入这条语句后执行`make qemu`的输出结果的差异,并解释为什么有差异或没差异?
{%s%}

* [x]
>
有差异。

intr_enable()函数通过sti命令开中断,在trap_dispatch()函数里,30这个数字执行到default里,print了各个寄存器的值后,调用panic()函数中止程序。

{%ends%}

(3)对于lab2的输出信息,请说明数字的含义

```
e820map:
memory: 0009fc00, [00000000, 0009fbff], type = 1.
memory: 00000400, [0009fc00, 0009ffff], type = 2.
memory: 00010000, [000f0000, 000fffff], type = 2.
memory: 07ee0000, [00100000, 07fdffff], type = 1.
memory: 00020000, [07fe0000, 07ffffff], type = 2.
memory: 00040000, [fffc0000, ffffffff], type = 2.
```
e820map:
memory: 0009fc00, [00000000, 0009fbff], type = 1.
memory: 00000400, [0009fc00, 0009ffff], type = 2.
memory: 00010000, [000f0000, 000fffff], type = 2.
memory: 07ee0000, [00100000, 07fdffff], type = 1.
memory: 00020000, [07fe0000, 07ffffff], type = 2.
memory: 00040000, [fffc0000, ffffffff], type = 2.

修改lab2,让其显示type="some string" 让人能够读懂,而不是不好理解的数字1,2 (easy)

修改lab2,让其显示`type="some string"` 让人能够读懂,而不是不好理解的数字1,2 \(easy\)
{%s%}

* [x]
>
type表示这块内存的Permission,type=1表示Kernel,type=2表示User

(4)\(spoc\)有一台只有页机制的简化80386的32bit计算机,有地址范围位0~256MB的物理内存空间(physical memory),可表示大小为256MB,范围为0xC0000000~0xD0000000的虚拟地址空间(virtual address space),页大小(page size)为4KB,采用二级页表,一个页目录项(page directory entry ,PDE)大小为4B,一个页表项(page-table entries PTEs)大小为4B,1个页目录表大小为4KB,1个页表大小为4KB。
{%ends%}

```
PTE格式(32 bit) :
PFN19 ... PFN0|NOUSE9 ... NOUSE0|WRITABLE|VALID
PDE格式(32 bit) :
PT19 ... PT0|NOUSE9 ... NOUSE0|WRITABLE|VALID
(4)(spoc)有一台只有页机制的简化80386的32bit计算机,有地址范围位0~256MB的物理内存空间(physical memory),可表示大小为256MB,范围为0xC0000000~0xD0000000的虚拟地址空间(virtual address space),页大小(page size)为4KB,采用二级页表,一个页目录项(page directory entry ,PDE)大小为4B,一个页表项(page-table entries PTEs)大小为4B,1个页目录表大小为4KB,1个页表大小为4KB。

其中:
NOUSE9 ... NOUSE0为保留位,要求固定为0
WRITABLE:1表示可写,0表示只读
VLAID:1表示有效,0表示无效
```
PTE格式(32 bit) :
PFN19 ... PFN0|NOUSE9 ... NOUSE0|WRITABLE|VALID
PDE格式(32 bit) :
PT19 ... PT0|NOUSE9 ... NOUSE0|WRITABLE|VALID

其中:
NOUSE9 ... NOUSE0为保留位,要求固定为0
WRITABLE:1表示可写,0表示只读
VLAID:1表示有效,0表示无效

假设ucore OS已经为此机器设置好了针对如下虚拟地址&lt;--&gt;物理地址映射的二级页表,设置了页目录基址寄存器(page directory base register,PDBR)保存了页目录表的物理地址(按页对齐),其值为0。ucore OS在物理内存空间(0x1000~0x41000)已经建立和配置好了整个二级页表(包括页目录表和页表),且页目录表的index为0x300~0x363的页目录项的\(PT19 ... PT0\)的值=\(index-0x300+1\)。
请写出一个translation程序(可基于python、ruby、C、C++、LISP、JavaScript等),输入是一个虚拟地址和一个物理地址,能够自动计算出对应的页目录项的index值,页目录项内容的值,页表项的index值,页表项内容的值。即\(pde\_idx, pde\_ctx, pte\_idx, pte\_cxt\)
假设ucore OS已经为此机器设置好了针对如下虚拟地址<-->物理地址映射的二级页表,设置了页目录基址寄存器(page directory base register,PDBR)保存了页目录表的物理地址(按页对齐),其值为0。ucore OS在物理内存空间(0x1000~0x41000)已经建立和配置好了整个二级页表(包括页目录表和页表),且页目录表的index为0x300~0x363的页目录项的(PT19 ... PT0)的值=(index-0x300+1)。

请写出一个translation程序(可基于python、ruby、C、C++、LISP、JavaScript等),输入是一个虚拟地址和一个物理地址,能够自动计算出对应的页目录项的index值,页目录项内容的值,页表项的index值,页表项内容的值。即(pde_idx, pde_ctx, pte_idx, pte_ctx)

请用如下值来验证你写的程序的正确性:

```
va 0xc2265b1f, pa 0x0d8f1b1f
va 0xcc386bbc, pa 0x0414cbbc
va 0xc7ed4d57, pa 0x07311d57
va 0xca6cecc0, pa 0x0c9e9cc0
va 0xc18072e8, pa 0x007412e8
va 0xcd5f4b3a, pa 0x06ec9b3a
va 0xcc324c99, pa 0x0008ac99
va 0xc7204e52, pa 0x0b8b6e52
va 0xc3a90293, pa 0x0f1fd293
va 0xce6c3f32, pa 0x007d4f32
```
va 0xc2265b1f, pa 0x0d8f1b1f
va 0xcc386bbc, pa 0x0414cbbc
va 0xc7ed4d57, pa 0x07311d57
va 0xca6cecc0, pa 0x0c9e9cc0
va 0xc18072e8, pa 0x007412e8
va 0xcd5f4b3a, pa 0x06ec9b3a
va 0xcc324c99, pa 0x0008ac99
va 0xc7204e52, pa 0x0b8b6e52
va 0xc3a90293, pa 0x0f1fd293
va 0xce6c3f32, pa 0x007d4f32

参考的输出格式为:

```
va 0xcd82c07c, pa 0x0c20907c, pde_idx 0x00000336, pde_ctx 0x00037003, pte_idx 0x0000002c, pte_ctx 0x0000c20b
```
va 0xcd82c07c, pa 0x0c20907c, pde_idx 0x00000336, pde_ctx 0x00037003, pte_idx 0x0000002c, pte_ctx 0x0000c20b

>> 注意:上述参考输出只是表示了正确的格式,其数值并不正确。


---

## 开放思考题
开放思考题

---

(1)请简要分析Intel的x64 64bit体系结构下的分页机制是如何实现的
(1)请简要分析Intel的x64 64bit体系结构下的分页机制是如何实现的

```
+ 采分点:说明Intel x64架构的分页机制的大致特点和页表执行过程
- 答案没有涉及如下3点;(0分)
- 正确描述了x64支持的物理内存大小限制(1分)
- 正确描述了x64下的多级页表的级数和多级页表的结构(2分)
- 除上述两点外,进一步描述了在多级页表下的虚拟地址-->物理地址的映射过程(3分)
```
+ 采分点:说明Intel x64架构的分页机制的大致特点和页表执行过程
- 答案没有涉及如下3点;(0分)
- 正确描述了x64支持的物理内存大小限制(1分)
- 正确描述了x64下的多级页表的级数和多级页表的结构(2分)
- 除上述两点外,进一步描述了在多级页表下的虚拟地址-->物理地址的映射过程(3分)

* [x]
>
{%s%}

根据Intel开发人员手册,x64理论上最大支持2^64(16EB),但实际上大多数操作系统并未实现对这么大内存空间的寻址,比如Windows现在只实现了16TB的内存寻址。

64位寻址模式(长模式),是物理地址扩展(PAE)的超集,因此,内存页大小可以是4KB,2MB,或1GB。但是,与系统在PAE模式下使用的三级标签页表机制不同,长模式下系统使用四级标签页表:PAE的页目录指针表的表项从4个扩展到了512个,而且附加了一个第四级页面映射表(Page-Map Level 4 Table,PML4 Table),包含512个采用48位实现的表项。在提供更大虚拟地址的实现中,这个表既可以进行扩展来提供足够数量的表项(对于64位实现来说理论值高达33,554,432个)以描述整个地址空间,也可以再被一个更高层映射级所映射,像是PML5。整个48位地址空间的4KB页面完整映射层级将会占据略多于512GB的内存(256TB虚拟地址空间的0.196%)。

{%ends%}

(2)Intel8086不支持页机制,但有hacker设计过包含未做任何改动的8086CPU的分页系统。猜想一下,hacker是如何做到这一点的?提示:想想MMU的逻辑位置

* [x]
>
{%s%}

MMU使能后,在CPU发出访存信号后截获,并根据页机制去获得真正的物理地址,然后访存。可以在编译的中间层对所有的访存指令中要访问的内存地址进行重新解释,解释为页机制下的地址,即某些为为页表项,其它位为偏移量。

{%ends%}

---

## v9-cpu相关
v9-cpu相关

[challenge]在v9-cpu上,设定物理内存为64MB。在os2.c和os4.c的基础上实现页机制管理,内核空间的映射关系: kernel_virt_addr=0xc00000000+phy_addr,内核空间大小为64MB,虚拟空间范围为0xc0000000--x0xc4000000, 物理空间范围为0x00000000--x0x04000000;用户空间的映射关系:user_virt_addr=0x40000000+usr_phy_addr,用户空间可用大小为1MB,虚拟空间范围为0x40000000--0x40100000,物理空间范围为0x02000000--x0x02100000。可参考v9-cpu git repo的testing分支中的os.c和mem.h。修改代码为os5.c

\[challenge\]在v9-cpu上,设定物理内存为64MB。在os2.c和os4.c的基础上实现页机制管理,内核空间的映射关系: kernel\_virt\_addr=0xc00000000+phy\_addr,内核空间大小为64MB,虚拟空间范围为0xc0000000--x0xc4000000, 物理空间范围为0x00000000--x0x04000000;用户空间的映射关系:user\_virt\_addr=0x40000000+usr\_phy\_addr,用户空间可用大小为1MB,虚拟空间范围为0x40000000--0x40100000,物理空间范围为0x02000000--x0x02100000。可参考v9-cpu git repo的testing分支中的os.c和mem.h。修改代码为[os5.c](https://github.com/chyyuu/v9-cpu/blob/master/root/usr/os/os5.c)
- (1)在内核态可正确访问这两个空间
- (2)在用户态可正确访问这两个空间
- [x]

* \(1\)在内核态可正确访问这两个空间
* \(2\)在用户态可正确访问这两个空间

* [x]
>

在使能页机制的前一条指令和后一条指令的内存地址的访问会出现什么不同/变化?

* [x]
>
- [ ]



如果在建立页表过程中,使能页机制前,如果不加上pg_dir[0]=....,为何v9-cpu模拟器会出现"kernel stack fault"的fatal error并推出?

- [ ]


如果在建立页表过程中,使能页机制前,如果不加上`pg_dir[0]=....`,为何v9-cpu模拟器会出现"kernel stack fault"的fatal error并推出?

* [x]
>
- 请比较一下os在v9-cpu和x86上建立页表过程的不同之处,需要考虑硬件设计上的差异
- [x]

* 请比较一下os在v9-cpu和x86上建立页表过程的不同之处,需要考虑硬件设计上的差异
* [x]
>