|
6.828的工具都装好了,在正式开始实验之前,要先熟悉每个工具的使用。对于我这种小白用户,需要熟悉的更多。
1、x86汇编语言
果然,课程首先让我熟悉汇编语言,并提供了两份参考文献。虽然我对汇编语言离熟悉还差十万八千里,不过好歹是用过的。我感到如果想要保持学习的兴趣,目前采取“如无必要,绝不深究”的态度非常重要。所以对汇编语言就先这样。我把参考文献下载到本地,然后跳到下一步。
2、模拟x86
课程给出了QEMU的作用、特性和辅助调试工具(GDB),不过这些细节我现在还统统不感兴趣。程序能跑起来才是我目前最关心的。
结果悲剧了。课程中使用的编译环境和我自己搭建的不一样,里面的操作基本用不了。既然easy way走不通,只好开启hard模式了。直接看QEMU的文档吧。
(1)QEMU文档的部分内容
a. QEMU是什么
QMEU是处理器的模拟器,它最大的特色就是快。也许这就是课程选择它作为目标机模拟器的原因吧。
QMEU有两种操作模式:全系统模拟和用户模式模拟。
b. QEMU可以模拟什么
从给出的列表来看,可模拟的设备相当多。因为我对计算机系统的硬件了解有限,这些设备还只是名字而已。
c. 启动系统镜像
重点来了,文档里对系统镜像的启动只有三行。
第一行:下载并解压linux镜像(linux.img);
第二行:执行qemu-system-i386 linux.img;
第三行:linux将启动,并给出提示符。
看到这里,我的内心是崩溃的。如此简单,又如此困难。因为我既没找到下载linux镜像的方法,也不知道如何执行命令。
自己不行,就百度吧。这样,我找到了fatsheep9146的博客。好神奇啊,他也自学了6.828。既然前人都已经探过路了,为什么一定要自己走呢?
(2)fatsheep9146的方案
读了他的博客文章,发现开发环境和我的不一样。他是用VMware运行ubuntu,将它作为编译环境。然后再ubuntu中下载了QEMU来使用。这和我想的不一样啊,原来可以在虚拟系统中运行虚拟系统!
如果是这样,整个开发环境就好多了。下面按课程文档中给出的linux环境下载和安装QMEU的步骤
a. 克隆仓库 git clone http://web.mit.edu/ccutler/www/qemu.git -b 6.828-2.3.0;
b. 安装SDL开发库 sudo apt-get install libsdl1.2-dev
c. 配置QEMU ./configure --disable-kvm --target-list="i386-softmmu x86_64-softmmu"
里面只报了两个问题:
c++ compliler:sudo apt-get install g++
pixman:sudo apt-get install libpixman-1-dev
d. 执行make编译,然后执行sudo make install安装。
(3)运行实验中的镜像
首先cd到工作文件夹,然后克隆源代码
git clone https://pdos.csail.mit.edu/6.828/2014/jos.git lab
上面的命令会得到一个lab文件夹,进入这个文件夹,执行make编译,就得到kernel.img了。
要把内核镜像运行在QEMU上,需要继续在lab文件夹内执行make qemu。
大功告成!
3、一些技术细节
考虑到我不是来学软件使用的,因此技术细节也不能一点不看啊。
(1)计算机的物理地址空间
32位系统最大支持4G的物理地址空间,从0x00000000到0xFFFFFFFF。
具体的分配如下图
+------------------+ <- 0xFFFFFFFF (4GB)
| 32-bit |
| memory mapped |
| devices |
| |
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
| |
| Unused |
| |
+------------------+ <- depends on amount of RAM
| |
| |
| Extended Memory |
| |
| |
+------------------+ <- 0x00100000 (1MB)
| BIOS ROM |
+------------------+ <- 0x000F0000 (960KB)
| 16-bit devices, |
| expansion ROMs |
+------------------+ <- 0x000C0000 (768KB)
| VGA Display |
+------------------+ <- 0x000A0000 (640KB)
| |
| Low Memory |
| |
+------------------+ <- 0x00000000
标记为“low memory”的640KB空间是随机存取存储器。
从0x000A0000到0x000FFFFF的384KB空间为硬件保留,用于显示缓存以及非易失性存储器中保存的固件。这些保留的空间中,最重要的部分是(BIOS),占据从0x000F0000到0x000FFFFF的64KB空间。
在计算机的发展过程中,支持的物理空间越来越大,但为了保持对早期软件的兼容,后期的计算机都保持了低位1MB地址空间的结构。因此现代计算机的物理空间都有个“洞”,它的地址空间是从0x000A0000到0x00100000。
现代的计算机可以支持高于4GB的物理RAM,但由于设计的限制,实验中开发的操作系统JOS只能使用前256MB的物理空间,因此假设所有计算机都只具有32位地址空间。
(2)ROM中的BIOS
这一部分使用QEMU中的调试模块对IA-32兼容计算机的启动进行研究,做了一次调试实验。
实验的目的是确定BIOS的重要性。详细来说,就是所有的计算机通电或重启以后都会首先执行一条BIOS中的命令。
实验过程:
a. 打开两个终端,都定位到 lab 文件夹,然后分别执行make qemu-gdb和gdb。我猜是以调试模式运行QEMU和运行调试器GDB。以调试模式运行的QEMU在启动后就停在了第一条指令上,通过启动的调试器GDB可以看到QEMU的运行状态。
b. 调试器界面上显示的所有信息中,给出了QEMU正在执行的指令
[f000:fff0] 0xffff0:ljmp $0xf000,$0xe05b
由于BIOS的地址空间为0x000F0000到0x000FFFFF的64KB空间,因此计算机正在执行的是位于BIOS最高地址处的那条命令。但是为什么要这样呢?原因在于计算机刚启动时,RAM中还没有任何程序,只有ROM中BIOS可以执行。
//GDB的单步调试指令位si。
c. QEMU模拟的处理器启动以后,就进入了实模式(real mode),并将CS寄存器设定为0xf000,将IP寄存器设定为0xfff0,因此执行的第一条指令才会是0x000FFFFF中的指令。
其中,实模式的分段地址(CS:IP)与物理地址的转化算法为:
physical address = 16*CS + IP
d. 当BIOS完成所有可能的初始化工作后,它就开始寻找一个可启动设备,例如软盘、硬盘、cd。找到以后,BIOS就会读取盘中的boot loader,并把控制交给它。
(3)boot loader
计算机的软盘和硬盘都被分成了很多大小为512字节(byte)的扇区(sector)。扇区就是最小的传输单位,也就是说每个读操作或写操作对应的数据都以扇区为单位。可启动盘的第一个扇区呗称为启动扇区,里面存储了启动加载器(boot loader)的程序。
当BIOS找到可启动盘以后,就会将启动扇区中的512字节数据加载到物理地址为0x7c00到0x7cff的内存中,然后使用jmp指令跳转到[0000:7c00],并将控制权交给启动加载器。
由于cd-rom启动是在计算机进一步发展以后才实现的,因此可进行更负载的加载操作。但课程中不涉及,因此笔记中把这一部分略去。
课程中的启动加载器由一个汇编语言源文件boot/boot.S和一个c语言源文件boot/main.c组成,执行两项主要功能:
a. 启动加载器将处理器从实模式切换到32位的保护模式,执行模式切换的原因在于只有在受保护的32位模式中各软件才能方位所有高于1MB的物理地址空间。
//要充分理解实模式和32位的保护模式,需要对课程给出的计算机汇编语言参考文件进行一些了解。
b. 启动加载器通过x86的特殊I/O/指令(special I/O instructions)直接访问IDE硬盘设备,将内核读取出来。
//虽然本课程不涉及特殊设备的编程,但在实际操作系统开发的过程中,设备驱动的编写是非常重要的。
理解了启动加载器的源代码以后,看一看文件obj/boot/boot.asm。它是实际运行的启动加载器的反汇编(disassambly)结果。从反汇编文件中可以容易的看到所有启动加载器的代码存储在哪些物理空间中。
//GDB可使用b指令设置断点,如b *0x7c00。当运行到断点时,可以使用c和si指令继续执行:c指令使QEMU持续运行,直到下一个断点(或在GDB中按下ctrl+c),si N指令意思使执行N个指令。 |
|
|
|
|
|
|