Part2:Virtual Memory
首先要熟悉x86的保护模式的内存管理体系,也就是分段和页转换。
Exercise 2
如果您还不熟悉分段与分页,请查看“Intel 80386参考手册”的第5章和第6章。 仔细阅读有关页面转换和基于页面的保护的部分(5.2和6.4)。 我们建议您浏览有关细分的部分; 虽然JOS使用分页硬件进行虚拟内存和保护,但在x86上无法禁用分段转换和基于段的保护,因此您需要对它有基本的了解。
Intel 80386 Reference Programmer’s ManualTable of Contents
感觉x86的分段式特别复杂,配置起来很繁琐。 分页式相对来说就很清晰明了了,I like it.
虚拟、线性和物理内存
在x86术语中,虚拟地址由段选择器和段内偏移组成。 线性地址是段转换之后但在页转换之前获得的。 物理地址是在段和页面转换之后得到的,以及最终经过总线到达RAM的内容。
exercise 3
第一个窗口执行make qemu-gdb
, 第二个执行make gdb
. 然后第二个窗口执行c
在ctrl+c
终止程序。键入查看内存指令x/16xw 0xf0100000
:
(gdb) x/16xw 0xf0100000
0xf0100000 <_start+4026531828>: 0x1badb002 0x00000000 0xe4524ffe 0x7205c766
0xf0100010 <entry+4>: 0x34000004 0x2000b812 0x220f0011 0xc0200fd8
0xf0100020 <entry+20>: 0x0100010d 0xc0220f80 0x10002fb8 0xbde0fff0
0xf0100030 <relocated+1>: 0x00000000 0x112000bc 0x0056e8f0 0xfeeb0000
第二终端再按c
,保持程序的运行。 第一终端按ctrl+a c
出现qemu终端。
(qemu) xp/16xw 0x100000
0000000000100000: 0x1badb002 0x00000000 0xe4524ffe 0x7205c766
0000000000100010: 0x34000004 0x2000b812 0x220f0011 0xc0200fd8
0000000000100020: 0x0100010d 0xc0220f80 0x10002fb8 0xbde0fff0
0000000000100030: 0x00000000 0x112000bc 0x0056e8f0 0xfeeb0000
两个地址上的内容一致,故可以证明0xf0100000
虚拟地址映射到了0x100000
物理地址上。
一旦进入保护模式,所有的指针都会被解释成虚拟地址并由MMU翻译。
JOS内核通常需要将地址转换为不透明值或整数,而不需要对它们解引用,例如在物理内存分配器中。 有时这些是虚拟地址,有时它们是物理地址。 为了帮助规范代码,JOS源代码区分了两种情况:类型uintptr_t
表示不透明的虚拟地址,physaddr_t
表示物理地址。 这两种类型实际上只是32位整数(uint32_t
)的同义词,因此编译器不会阻止您将一种类型分配给另一种类型! 由于它们是整数类型(不是指针),如果您尝试对它们解引用,编译器就会给出警告或错误。
JOS内核可以通过首先将其转换为指针类型来解引用uintptr_t。 相反,内核不能明智地解引用物理地址,因为MMU会转换所有内存引用。 如果将physaddr_t转换为指针并解引用它,您可以加载并存储到结果地址(硬件会将其解释为虚拟地址),但您可能无法获得预期的内存位置。
Questions
Assuming that the following JOS kernel code is correct, what type should variable x have, uintptr_t or physaddr_t?
mystery_t x;
char