You've successfully subscribed to The Daily Awesome
Great! Next, complete checkout for full access to The Daily Awesome
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.
Success! Your billing info is updated.
Billing info update failed.

MIT6.828 | Lab 1: Booting a PC - Part 1: PC Bootstrap

. 4 min read

了解 x86 汇编语言 和 PC 开机引导(bootstrap)过程

QWMU x86 模拟器 started with QEMU and QEMU/GDB debugging

1. Getting Started with x86 assembly

汇编语言手册:The PC Assembly Language Book

We do recommend reading the section "The Syntax" in Brennan's Guide to Inline Assembly.

when reading and writing x86 assembly: the 6.828 reference page

80386 Programmer's Reference Manual

IA-32 Intel Architecture Software Developer's Manuals

available from AMD.

2. Simulating the x86

使用模拟器,代码可以在物理PC运行,支持断点debug等

In 6.828 we will use the QEMU Emulator, a modern and relatively fast emulator,which can act as a remote debugging target for the GNU debugger (GDB),

Ububtu 需要安装 32位gcc multilib : gcc-multilib package

Now you're ready to run QEMU, supplying the file obj/kern/kernel.img, created above, as the contents of the emulated PC's "virtual hard disk." This hard disk image contains both our boot loader (obj/boot/boot) and our kernel (obj/kernel).

启动模拟器: make qemu-nox

*** 
*** Use Ctrl-a x to exit qemu 
*** 
qemu-system-i386 -nographic -drive file=obj/kern/kernel.img,index=0,media=disk,format=raw -serial mon:stdio -gdb tcp::26000 -D qemu.log
6828 decimal is XXX octal! 
entering test_backtrace 5 
entering test_backtrace 4 
entering test_backtrace 3 
entering test_backtrace 2 
entering test_backtrace 1 
entering test_backtrace 0
leaving test_backtrace 0
leaving test_backtrace 1 
leaving test_backtrace 2
leaving test_backtrace 3 
leaving test_backtrace 4
leaving test_backtrace 5
Welcome to the JOS kernel monitor! 
Type 'help' for a list of commands. 
K>

Kernel Info:

K> kerninfo 
Special kernel symbols: 
  _start                  0010000c (phys)
  entry  f010000c (virt)  0010000c (phys)
  etext  f01019e9 (virt)  001019e9 (phys) 
  edata  f0113060 (virt)  00113060 (phys)
  end    f01136a0 (virt)  001136a0 (phys) 
Kernel executable memory footprint: 78KB
K>

3. PC 的物理地址空间

+------------------+  <- 0xFFFFFFFF (4GB)
|      32-bit      |
|  memory mapped   |
|     devices      |
|                  |
/\/\/\/\/\/\/\/\/\/\

/\/\/\/\/\/\/\/\/\/\
|                  |
|      Unused      |
|                  |
+------------------+  <- depends on amount of RAM
|                  |  为了兼容早期 1MB 的机型,这部分被划分为 Extended Memory
|                  |
| Extended Memory  |
|                  |
|                  |
+------------------+  <- 0x00100000 (1MB)
|     BIOS ROM     |  <- 64KB
+------------------+  <- 0x000F0000 (960KB)
|  16-bit devices, |
|  expansion ROMs  |
+------------------+  <- 0x000C0000 (768KB)
|   VGA Display    |
+------------------+  <- 0x000A0000 (640KB)
|                  |
|    Low Memory    |
|                  |
+------------------+  <- 0x00000000

现在的x86处理器可以支持4GB以上的物理RAM,因此RAM可以进一步扩展到0xFFFFFFFF以上。在这种情况下,BIOS必须安排在32位可寻址区域顶部的系统RAM中留下第二个孔,为这些32位设备留出空间。由于设计限制,无论如何,JOS将只使用PC的物理内存的第一个256MB,所以现在我们将假装所有PC“仅”拥有32位物理地址空间。但是处理复杂的物理地址空间和多年来发展的硬件组织的其他方面是OS开发的重要实际挑战之一。

4. The ROM BIOS (Basic Input/Output System)

使用QEMU的调试工具来研究IA-32兼容计算机的启动方式

打开两个终端:

enter make qemu-gdb (or make qemu-nox-gdb).

这将启动QEMU,但QEMU在处理器执行第一条指令之前停止,并等待来自GDB的调试连接。

在另一个终端 run make gdb

[f000:fff0]    0xffff0: ljmp   $0xf000,$0xe05b
0x0000fff0 in ?? ()
+ symbol-file obj/kern/kernel
(gdb)  

其中第一行为GDB反汇编出的第一条要执行的指令,从中可以发现:

  • 这台 IBM PC 从物理地址 0x0000_fff0 开始执行,由上图可知,它位于为ROM BIOS保留的64KB区域的最顶端。
  • PC 从 CS = 0xf000IP = 0xfff0 开始执行
  • 第一条执行的指令是 jmp, 他会跳转到分段地址 (segment address) CS = 0xf000 and IP = 0xe05b.

之所以这样模拟是因为Intel 8088处理器的BIOS位置绑定在了0x0000fff0, 保证了启动时首先由 BIOS 接管机器,而此时没有其他软件可以运行,因此需要跳转到指定地址

最终的跳转地址为:(CS:IP) => (0xf000:fff0) 映射的物理内存地址

这里应用了 实模式寻址(real mode addressing)

$\text{physical address} = 16 \times segment + offset $

即: (*16就是补0,segment可以参考cache block理解)

16 * 0xf000 + 0xfff0   		# in hex multiplication by 16 is
   = 0xf0000 + 0xfff0     	# easy--just append a 0.
   = 0x000ffff0 			# 16 bytes before the end of the BIOS (0x100000).

!> 练习二:使用gdb命令 si (Step instruction)追踪BIOS,需要结合 x86 汇编手册,暂时不看。

启动顺序:

After initializing the PCI bus and all the important devices the BIOS knows about, it searches for a bootable device such as a floppy, hard drive, or CD-ROM. Eventually, when it finds a bootable disk, the BIOS reads the boot loader from the disk and transfers control to it.