mit 6.828: lab1

安装 QEMU

使用 Ubuntu 16.04.

1
2
3
4
5
6
sudo apt install libglib2.0-dev libgcrypt20-dev zlib1g-dev gcc-multilib autoconf automake bison flex
sudo apt install libpixman-1-dev libz-dev libtool libtool-bin libsdl1.2-dev
git submodule update --init dtc
./configure --disable-kvm --target-list="i386-softmmu x86_64-softmmu" # 默认安装到 /usr/local
make -j8
make -j8 install

Software Setup

下载实验材料:

1
2
3
4
5
6
7
athena% mkdir ~/6.828
athena% cd ~/6.828
athena% add git
athena% git clone https://pdos.csail.mit.edu/6.828/2017/jos.git lab
Cloning into lab...
athena% cd lab
athena%

Part 1: PC Bootstrap

这一部分不需要编码,只为了让我们了解 PC bootstrap 的过程。并且让我们熟悉 QEMU 和 QEMU/GDB 的 debug 过程。

1
2
cd lab
make

这会 build 一个 boot loader 和 kernel : kernel.img

Simulating the x86

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
parallels@parallels-vm:~/Desktop/mit/lab$ make
+ as kern/entry.S
+ cc kern/entrypgdir.c
+ cc kern/init.c
+ cc kern/console.c
+ cc kern/monitor.c
+ cc kern/printf.c
+ cc kern/kdebug.c
+ cc lib/printfmt.c
+ cc lib/readline.c
+ cc lib/string.c
+ ld obj/kern/kernel
+ as boot/boot.S
+ cc -Os boot/main.c
+ ld boot/boot
boot block is 390 bytes (max 510)
+ mk obj/kern/kernel.img

kernel.img 包含了 boot loader (obj/boot/boot) 和 kernel (obj/kernel)。

然后使用命令:

1
2
3
make qemu
or
make qemu-nox

为了退出,使用命令 Ctrl+a x

在当前的 kernel 里面,可以使用如下两个命令:

1
2
3
4
5
6
7
8
9
10
11
12
K> help
help - Display this list of commands
kerninfo - Display information about the kernel
K> kerninfo
Special kernel symbols:
_start 0010000c (phys)
entry f010000c (virt) 0010000c (phys)
etext f0101871 (virt) 00101871 (phys)
edata f0112300 (virt) 00112300 (phys)
end f0112944 (virt) 00112944 (phys)
Kernel executable memory footprint: 75KB
K>

The PC’s Physical Address Space

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
     +------------------+  <- 0xFFFFFFFF (4GB)
| 32-bit |
| memory mapped |
| devices |
| |
/\/\/\/\/\/\/\/\/\/\

/\/\/\/\/\/\/\/\/\/\
| |
| Unused |
| |
+------------------+ <- depends on amount of RAM
| |
| |
| Extended Memory |
| |
| |
--- +------------------+ <- 0x00100000 (1MB)
| | BIOS ROM |
| +------------------+ <- 0x000F0000 (960KB)
hole | 16-bit devices, |
| | expansion ROMs |
| +------------------+ <- 0x000C0000 (768KB)
| | VGA Display |
--- +------------------+ <- 0x000A0000 (640KB)
| |
| Low Memory |
| |
+------------------+ <- 0x00000000

The first PCs, which were based on the 16-bit Intel 8088 processor, were only capable of addressing 1MB of physical memory. The physical address space of an early PC would therefore start at 0x00000000 but end at 0x000FFFFF instead of 0xFFFFFFFF. The 640KB area marked "Low Memory" was the only random-access memory (RAM) that an early PC could use; in fact the very earliest PCs only could be configured with 16KB, 32KB, or 64KB of RAM!

The 384KB area from 0x000A0000 through 0x000FFFFF was reserved by the hardware for special uses such as video display buffers and firmware held in non-volatile memory. The most important part of this reserved area is the Basic Input/Output System (BIOS), which occupies the 64KB region from 0x000F0000 through 0x000FFFFF. In early PCs the BIOS was held in true read-only memory (ROM), but current PCs store the BIOS in updateable flash memory. The BIOS is responsible for performing basic system initialization such as activating the video card and checking the amount of memory installed. After performing this initialization, the BIOS loads the operating system from some appropriate location such as floppy disk, hard disk, CD-ROM, or the network, and passes control of the machine to the operating system.

When Intel finally “broke the one megabyte barrier” with the 80286 and 80386 processors, which supported 16MB and 4GB physical address spaces respectively, the PC architects nevertheless preserved the original layout for the low 1MB of physical address space in order to ensure backward compatibility with existing software. Modern PCs therefore have a "hole" in physical memory from 0x000A0000 to 0x00100000, dividing RAM into “low” or “conventional memory” (the first 640KB) and “extended memory” (everything else). In addition, some space at the very top of the PC’s 32-bit physical address space, above all physical RAM, is now commonly reserved by the BIOS for use by 32-bit PCI devices.

Recent x86 processors can support more than 4GB of physical RAM, so RAM can extend further above 0xFFFFFFFF. In this case the BIOS must arrange to leave a second hole in the system’s RAM at the top of the 32-bit addressable region, to leave room for these 32-bit devices to be mapped. Because of design limitations JOS will use only the first 256MB of a PC’s physical memory anyway, so for now we will pretend that all PCs have “only” a 32-bit physical address space. But dealing with complicated physical address spaces and other aspects of hardware organization that evolved over many years is one of the important practical challenges of OS development.

The ROM BIOS

这部分用来探索 IA-32 兼容的电脑是怎么启动的。

首先进入 lab 目录,打开两个 terminal。

  • In one, enter make qemu-gdb (or make qemu-nox-gdb). This starts up QEMU, but QEMU stops just before the processor executes the first instruction and waits for a debugging connection from GDB.
  • In the second terminal, from the same directory you ran make, run make gdb. You should see something like this:
1
2
3
4
5
6
7
8
9
parallels@parallels-vm:~/Desktop/mit/lab$ make gdb
gdb -n -x .gdbinit
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
...
The target architecture is assumed to be i8086
[f000:fff0] 0xffff0: ljmp $0xf000,$0xe05b
0x0000fff0 in ?? ()
+ symbol-file obj/kern/kernel
(gdb)

我们来看下PC boot 时候的这个第一条指令:

1
[f000:fff0] 0xffff0:	ljmp   $0xf000,$0xe05b

从这条指令可以看出如下几点:

  • The IBM PC starts executing at physical address 0x000ffff0, which is at the very top of the 64KB area reserved for the ROM BIOS.
  • The PC starts executing with CS = 0xf000 and IP = 0xfff0.
  • The first instruction to be executed is a jmp instruction, which jumps to the segmented address CS = 0xf000 and IP = 0xe05b.

On processor reset, the (simulated) processor enters real mode and sets CS to 0xf000 and the IP to 0xfff0, so that execution begins at that (CS:IP) segment address.

Part 2: The Boot Loader

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.

If the disk is bootable, the first sector of the disk is called the boot sector, since this is where the boot loader code resides.

When the BIOS finds a bootable floppy or hard disk, it loads the 512-byte boot sector into memory at physical addresses 0x7c00 through 0x7dff, and then uses a jmp instruction to set the CS:IP to 0000:7c00, passing control to the boot loader.

For 6.828, the bootload code is in boot/boot.s and boot/main.c. The bootloader perform two main functions:

  1. switch from real mode to 32bit protected mode, so the software can access memory above 1MB. And the segmented addresses change from 16bit to 32bit.
  2. boot loader reads kernel from hard disk.
0%