【BUAA-OS】lab2-内存管理
发表于:2023-04-02 | 分类: BUAA操作系统
字数统计: 1.9k | 阅读时长: 7分钟 | 阅读量:

BUAA-OS lab2实验报告,关于mos系统的内存管理机制的实现,内存初始化,二级页表,TLB重填等内容。

lab2_log

思考题

Thinking2.1

Thinking 2.1 请根据上述说明,回答问题:在编写的 C 程序中,指针变量中存储的地址是虚拟地址,还是物理地址?MIPS 汇编程序中 lw 和 sw 使用的是虚拟地址,还是物理地址?

  • 都是虚拟地址,因为CPU只会发出虚拟地址,虚拟地址都需要经过映射才会得到物理地址。

Thinking2.2

Thinking 2.2 请思考下述两个问题:
• 从可重用性的角度,阐述用宏来实现链表的好处。
• 查看实验环境中的 /usr/include/sys/queue.h,了解其中单向链表与循环链表的实现,比较它们与本实验中用的双向链表,分析三者在插入与删除操作上的性能差异。

  • 使用宏定义对链表的操作进行封装,提高了代码的可重用性,提高了可读性。
  • 单项链表只能获取每一项的后一项,所以在某项前插入与删除的操作只能从头开始遍历链表,但可以在后一项直接插入。
  • 循环链表删除插入性能与单向链表一致,但是由于有尾部指针,所以在最后一项上插入开销小。
  • 双向链表在某项前后的插入操作以及对某项的删除操作都只有O(1)的开销。

Thinking2.3

Thinking 2.3 请阅读 include/queue.h 以及 include/pmap.h, 将 Page_list 的结构梳理清楚,选择正确的展开结构。

  • 我选择C结构,Page_list的结构体中有一个指向表头的指针,然后每一个页的项由一个包含两个指针的pp_link与一个表示索引次数的pp_ref表示。
1
2
3
4
5
6
7
8
9
struct Page_list{
struct {
struct {
struct Page *le_next;
struct Page **le_prev;
} pp_link;
u_short pp_ref;
}* lh_first;
}

Thinking2.4

Thinking 2.4 请思考下面两个问题:
• 请阅读上面有关 R3000-TLB 的描述,从虚拟内存的实现角度,阐述 ASID 的必要性。
• 请阅读《IDT R30xx Family Software Reference Manual》的 Chapter 6,结合 ASID段的位数,说明 R3000 中可容纳不同的地址空间的最大数量。

  • address identifier必要性:在操作系统中,同一虚拟地址在不同的地址空间中会映射到不同的物理地址上,每个进程会有自己的虚拟地址空间,所以需要用ASID来区别改虚拟地址是在哪个进程中。
  • ASID在EntryHi中占了6位,所以最大可以容纳64个地址空间。

Thinking2.5

Thinking 2.5 请回答下述三个问题:
• tlb_invalidate 和 tlb_out 的调用关系?
• 请用一句话概括 tlb_invalidate 的作用。
• 逐行解释 tlb_out 中的汇编代码。

  • tlb_invalidata调用了tlb_out。
  • 在页表内容改变后删除它在TLB中的旧表项。
  • tlb_out代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
LEAF(tlb_out)
.set noreorder
mfc0 t0, CP0_ENTRYHI
mtc0 a0, CP0_ENTRYHI
nop
tlbp
nop
mfc0 t1, CP0_INDEX
.set reorder
bltz t1, NO_SUCH_ENTRY
.set noreorder
mtc0 zero, CP0_ENTRYHI
mtc0 zero, CP0_ENTRYLO0
nop
tlbwi
.set reorder

NO_SUCH_ENTRY:
mtc0 t0, CP0_ENTRYHI
j ra
END(tlb_out)
  • tlb_out由tlb_invalidate调用,主要作用就是清空TLB表项。
  • 首先将cp0_entryHI的原来的值存在t0寄存器中,我们看后面可以知道主要是为了找不到的时候恢复原样用的。
  • 然后就是把a0这个传入的参数写入cp0_entryHI随后用tlbp查找,得到索引值,如果大于等于0,就是找到了。
  • 然后我们就可以将cp0_entryHI和cp0_entryLO都置为0,最后用tlbwi将值写到index位置的tlb里,达到清零的目的。

Thinking2.6

Thinking 2.6 任选下述二者之一回答:
• 简单了解并叙述 X86 体系结构中的内存管理机制,比较 X86 和 MIPS 在内存管理上的区别。
• 简单了解并叙述 RISC-V 中的内存管理机制,比较 RISC-V 与 MIPS 在内存管理上的区别。

  • 理论课上提到了x86的内存管理机制,x86架构采用的是段页式管理机制,mips采用页式管理。
  • 而且x86的页映射机制是可选的,可以通过CR0寄存器的PG位来设置。
  • 除了段式的差别之外,x86的页式内存管理也与mips的有所不同,对于TLB不命中的处理机制上,mips会触发异常后TLB重填,然后第二次访问。而x86会直接索引CR3得到页目录基址,得到目标的PFN,然后再来重填TLB。

ThinkingA.1

Thinking A.1 在现代的 64 位系统中,提供了 64 位的字长,但实际上不是 64 位页式存储系统。假设在 64 位系统中采用三级页表机制,页面大小 4KB。由于 64 位系统中字长为8B,且页目录也占用一页,因此页目录中有 512 个页目录项,因此每级页表都需要 9 位。因此在 64 位系统下,总共需要 3 × 9 + 12 = 39 位就可以实现三级页表机制,并不需要 64位。
现考虑上述 39 位的三级页式存储系统,虚拟地址空间为 512 GB,若三级页表的基地址为 PTbase,请计算:
• 三级页表页目录的基地址。
• 映射到页目录自身的页目录项(自映射)。

  • 三级页表页目录的基地址为: $PT_{base} + PT_{base} << 9 + PT_{base} << 18$
  • 映射到页目录自身的页表项: $PT_{base} + PT_{base} << 9 + PT_{base} << 18 + PT_{base} << 27 $

难点分析

  • 这次主要要操作的文件为include/queue.c与kern/pmap.c,但同时,我们离不开include/mmu.h与include/pmap.h中定义的宏。

Exercise2.1-2.5

  • 这里主要需要完成内核初始化mips_init()中的两个函数
  • mips_detect_memory()
  • page_init()

  • 主要利用BY2PG宏,定义在mmu.h中,代表页面的大小。

  • 然后就是实现双向链表宏,为后续做准备。

  • 理解Page结构体的引导的链表项,指向的应该是物理空闲页的页号,通过pmap.h中的两个函数page2pa与pa2page完成于物理页面号与物理地址之间的转换。

  • 然后就是完成管理物理内存的四个函数

  • page_init, page_alloc, page_decref, page_free

Exercise2.6-2.7

  • 这里主要就是虚拟内存管理的结构,我们要实现一个两级页表,一级页目录(PD),一级页表(PT),可以用PDX(va)和PTX(va)来获取一个虚拟地址的页目录号和页表号,即第31-22位与第21-12位。
  • 用Pde与Pte来表示页目录项及页表项。其实就是u_long。
  • MOS的满页不会置换,而是直接报错。
  • pgdir_walk函数的功能是完成页目录项到页表项的映射。
  • page_insert函数完成的是建立起页表与实际页控制块对应的物理页面的映射。

Exercise2.8-2.10

  • TLB重填,指导书说的挺清楚的,看懂mips的汇编代码就好了~

实验体会

  • 相较于lab1,lab2难度上增加很大,首先就是课下实验花费了大量的时间,但是很多地方还是不理解,我觉得最主要的还是先理解理论知识,得要先学会二级页表的寻址的规则,自映射的规则,不然会很难看懂源代码的意思。而且还有许多宏定义,一定要确保看过源代码,知道这个宏的用途。所以工作量还是很大的,但还是给自己留下了一点教训吧,os还是真的必须重视理论,这是一切的基础!而且得花时间!
上一篇:
【BUAA-OO】ElevatorDispatcher3.0
下一篇:
【BUAA-OO】ElevatorDispatcher2.0