操作系统也是程序 (调试Firmware和Bootloader)
在OS Lab Couse 1中我们已经构建了一个最小的hello world程序
|
用一种比较特殊的编译方式 (-Wl,
会把后面的东西传给连接器)
gcc a.c -static -Wl,--entry=main |
编译生成可执行文件,然后用readelf
查看ELF文件, 可以看到Entry point address是0x401ce5
用objdump
反汇编查看改地址对应的位置,确实是以main函数entry point
运行程序,程序依然能够正常执行
./a.out; echo $? |
回到程序=状态机
是谁创建了状态机
必然是操作系统,操作系统加载了上述程序
但是操作系统也是个程序,他又由谁加载?
Bare-Metal 与程序员的约定
为了让计算机能运行任何我们的程序,一定存在一些软件/硬件的约定
CPU Reset
-
CPU reset后,处理器处于某个确定的状态
-
- PC指针一般指向一段memory-mapped ROM
-
-
- ROM存储了厂商提供的firmware(固件)
-
-
- 处理器的大部分特性处于关闭状态
-
-
- 缓存,虚拟存储,…
-
老式的计算机有一个电源按钮,还有一个小的reset按钮。之前电脑启动有冷启动和热启动的概念。冷启动,按电源按钮,此时也会包含一个reset过程。热启动,电脑死机,按reset。
Fireware
-
- 将用户数据加载到内存
-
-
- 例如存储介质上的第二级loader
- 或者直接加载操作系统(嵌入式系统)
-
CPU Reset行为
寄存器会有初始状态
-
EIP = 0x000ffff0
-
CR0 = 0x60000010 (表明16 bit模式)
-
EFLAGS = 0x00000002
-
- interrupt disabled
CPU Reset之后,发生了什么
从 PC(CS:IP)指针处取指令,译码,执行
从firware开始执行
- CPU Reset后EIP指向的ffff0通常是一条向firmware跳转的Jump指令
Firmware: BIOS vs. UEFI
-
都是主板/主板上外插设备的软件抽象
-
- 支持系统管理程序运行
-
Legacy BIOS (Basic I/O System)
-
UEFI (Unified Extensible Firmware Interface)
调试qemu, 确认Firmware的行为
提供了两个文件
- run_qemu.sh
- hello.img
run_qemu.sh的内容
!/bin/bash |
hello.img的内容
xxd hello.img |
最后有一个55aa, 表明可启动,不是55aa则不可启动
- 开始调试
bash run-qemu.sh hello.img |
CPU Reset
查看寄存器,发现此时eip是0xfff0, cs是0xf000
(gdb) info registers |
用 x/i ($cs * 16 + $eip)
打印当前指令,这是一条jump指令
用 x/10i ($cs * 16 + $eip)
打印当前开始的10条指令
- firmware会把磁盘的前512字节搬到内存0x7c00的位置,查看这个过程
用x/16xb 0x7c00
打印内存
通过watch *0x7c00
在0x7c00出打一个监视点,然后继续执行
(gdb watch 借助观察断点可以监控程序中某个变量或者表达式的值,只要发生改变,程序就会停止执行)
程序停止,查看当前指令
查看0x7c00处内存
单步执行,随着程序的不断运行,越来越多的字节被搬运到0x7c00
对比hello.img,搬运进去的正是hello.img的内容
firmware完成任务之后,寄存器cs=0, ip=7c00
Firmware的另一些用处
放置一些 “绝对安全的代码”
-
BIOS 中断 (Hello World 是如何被打印的)
-
ARM TrustZone
-
Intel ME (不太正确的 “Ring -3”)
- 据说 “每个 Intel 芯片组里都藏着一个 Minix3 操作系统”
Firmware病毒
Intel 430TX (Pentium) 芯片组允许写入 Flash ROM
-
只要向 Flash BIOS 写入特定序列,Flash ROM 就变为可写
- 留给 firmware 更新的通道
-
要得到这个序列其实并不困难
- 似乎文档里就有,还可以解析 BIOS 的更新程序
- Boom…… (CPU RESET 之后就……了)