6.828 Lab1

Notes:

本笔记主要侧重于内容的记录,对于环境的搭建等可能不完整,建议根据每个lab的link进行配置。

由于这是MIT fall的课程,建议使用前一年的git和 intro等。

Part 1: PC Bootstrap

The PC’s Physical Address Space

PC的物理地址空间如下:

lab1-1

在早期的基于16位的Intel 8088处理器PC只能操作1MB的物理内存,它的地址空间位于0x000000000x000FFFFF,而不是现在的0xFFFFFFFF。从0x000000000x00A0000这640KB的空间被标注为"Low Memory”,这是一块只能被RAM访问的地址。(emm,有没有大佬告诉我这是干嘛用的?

0x000A0000上面到0x000FFFFF这384KB的空间被留作硬件的使用,例如VGA显示亦或是存储于非易失存储器的硬件等。这其中最重要的是位于0x000F00000x0010000的64KB的BIOS(Basic Input/Output System),早期PC中BIOS运行于ROM中,但现在PC一般运行于闪存上,负责完成基本的系统初始化(如访问声卡、计算安装的内存大小等)。完成了这样的初始化以后,BIOS从合适的位置(软盘、硬盘、CD-ROM、网络等)载入操作系统然后把机器的控制权交给操作系统。

虽然现代的CPU支持4GB甚至更多的物理地址空间,PC为了提供向后兼容仍然保留了原来的最低1MB物理地址空间的布局结构。故而现代CPU会在0x000A00000x00100000留一个洞,前640KB作为Low Memory,1MB以后作为扩展内存。

而对于支持超过4GB物理RAM的处理器,RAM的范围就不仅仅是上图的0xFFFFFFFF了。这种情况下,BIOS必须在32位物理地址空间的最高部分留下第二个洞,用于32位外设的映射。

The ROM BIOS

通过观察GDB反汇编的第一条执行指令:

[f000:fff0] 0xffff0:	ljmp   $0xf000,$0xe05b
  • IBM PC从物理地址为0x000ffff0处开始执行
  • PC的偏移为 CS=0xf000 IP=0xfff0
  • 第一条指令为跳转到段地址为CS=0xf000 IP=0xfff0的jmp指令

CS为代码段寄存器,IP为指令寄存器

这样确保了在PC启动时,BIOS得到控制权对系统进行一系列的初始化。

0xf000:fff0是怎么转换成物理地址的呢?回忆一下系统结构的知识,我们需要一点关于实模式的知识。

实模式(real mode)是PC加电启动以后仅具有16位寻址能力,并且不区分用户态和内核态,指针均指向实际物理地址。

physical address = 16 * segment + offset

16 * 0xf000 + 0xfff0
= 0xf0000 + 0xfff0
= 0xffff0

在BIOS初始化IDT(Interrupt Descriptor Table)和不同的设备时,输出Starting SeaBIOS信息。完成对PCI总线和设备初始化后,它开始寻找一个可启动的设备,从中找到boot loader并转交控制权。

Part 2: The Boot Loader

硬盘被分为每512B一个sector,这是磁盘划分的最小单位,如果这个盘是可启动的,那么它的第一个sector被称为boot sector,BIOS就会载入这个sector到物理地址为0x7c000x7dff的内存中,然后通过jmp指令并设置CS:IP0000:7c00。顺便一提,若从CD-ROM启动,则会使用2048B的sector。

boot loader包括一个汇编文件boot/boot.S和C文件boot/main.c,它们主要有以下两个作用:

  • 把处理器从实模式转变为32位的保护模式,这种模式下,软件才能够访问到高于1MB的内存地址。
  • 从硬盘中读取kernel到内存,并向其转移控制。

Loading the Kernel

这里介绍了ELF(Executable and Linking Format)文件格式。在编译器把C编译成.o文件后,链接器会把这些文件链接成一个二进制映像(例如obj/kern/kernel),

编译产生的.o文件虽然已经是二进制文件,但是有些函数的入口地址还没有找到,并不能直接执行。

链接阶段主要是链接函数和全局变量。

ELF文件分为ELF header, Program header table, Section header table和对应的Program/Section table entry指向程序或控制数据。ELF文件具有如下两种视图: lab1-2

其中,ELF header位于文件头部,用于描述文件整体结构;

Program headers用于内核构造进程的内存镜像;

Section保存object文件linking view的信息,包括指令、数据、符号表等。

我们使用objdump -h obj/kern/kernel查看各个section的header信息:

lab1-3

注意.text段VMA和LMA分别表示了链接地址和加载地址。链接地址指程序运行的虚拟地址,而LMA是程序载入内存的物理地址,修改VMA则会程序崩溃。

Part 3: The Kernel

不同于boot loader链接地址等于加载地址,kernel往往为了处理器留下低地址空间给用户进程而跑在较高的虚拟地址0xf0100000。而只是映射在较低的0x00100000物理地址。

Reference

Synchronous Practice Repo: 6.828Lab

Course Web: https://pdos.csail.mit.edu/6.828/2016/schedule.html

Video: https://pdos.csail.mit.edu/6.828/2011/schedule.html

xv6-chinese: https://github.com/ranxian/xv6-chinese

make命令教程: http://www.ruanyifeng.com/blog/2015/02/make.html

PC Assembly Language(NASM assembler): https://pdos.csail.mit.edu/6.828/2016/readings/pcasm-book.pdf

A20很棒的科普文章: http://blog.theerrorlog.com/the-funny-design-of-a20.html

Exercise的部分解析: http://xinqiu.me/2016/10/15/MIT-6.828-1/

ELF文件: http://hustcat.github.io/getting-into-core-dump-file/

Avatar
Yang Li
@zjzsliyang