复习
本次课回答的问题
本次课主要内容
热身实验
正经实验
心路历程
韩寒:“被小学生支配的恐惧,而我也曾对那种力量,一无所知。”
- 「护球像梅西,射门像贝利」的金山区齐达内,满怀期待地去和儿童预备队比赛,结果被灌了 20 多球。
Bill Gates: 我选择退学。
将已有的知识和方法重新消化,为大家建立好 “台阶”,在有限的时间里迅速
赶上数十年来建立起的学科体系 。
今天的学术界可比 Bill Gates 的时代卷多了
例子:破除 “写操作系统很难”、“写操作系统很牛” 的错误认识
“专业世界观” 的例子 (这些都没啥,paper 都发不了)
“专业世界观” 的学习方法
我们已经知道如何写一个 “最小” 的 C 程序了:
“程序 = 状态机” 没问题
为了让计算机能
CPU Reset (Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A/3B)
EIP = 0x0000fff0
CR0 = 0x60000010
EFLAGS = 0x00000002
《计算机系统基础》:
CS:IP
) 指针处取指令、译码、执行……ffff0
通常是一条向 firmware 跳转的 jmp 指令Firmware: BIOS vs. UEFI
Firmware 必须提供机制,将用户数据载入内存
7c00
位置CS:IP = 0x7c00
, (R[CS] << 4) | R[IP] == 0x7c00
CS = 0x07c0, IP = 0
CS = 0, IP = 0x7c00
Talk is cheap. Show me the code. ——Linus Torvalds
有没有可能我们真的去看从 CPU Reset 以后每一条指令的执行?
亲眼确认 Firmware 到底是不是会加载启动盘第一个扇区到
0x7c00
内存位置!
调试 QEMU 模拟器
info registers
0x7c00
内存的加载watch *0x7c00
- 《计算机系统基础》的良苦用心x/i ($cs * 16 + $rip)
x/16xb 0x7c00
0x7c00
代码的执行b *0x7c00
, c
(撒花!我们一会再回来)Firmware 通常是只读的 (当然……)
CIH 的作者陈盈豪被逮捕,但并未被定罪
IBM PC 所有设备/BIOS 中断是有 specification 的 (成就了 “兼容机”)
标准化的加载流程
.efi
更好的程序支持
Firmware 和 boot loader 共同完成 “操作系统的加载”
heap
)main
函数传递参数进入 C 代码之后
一个迷你 “操作系统” thread-os.c
int main() {
cte_init(on_interrupt);
for (int i = 0; i < LENGTH(tasks); i++) {
Task *task = &tasks[i];
Area stack = (Area) { &task->context + 1, task + 1 };
task->context = kcontext(stack, task->entry, (void *)task->name);
task->next = &tasks[(i + 1) % LENGTH(tasks)];
}
mpe_init(mp_entry);
}
TRM + MPE
CTE
on_interrupt
会拦截到中断事件VME
如果使用 “土办法”,你很可能被淹没在 Makefile 中
- 读懂 Makefile 需要 STFW, RTFM,大量的精力
- 虽然花点时间读是值得的,但很可能读了很久都没读到重要的地方
花一点时间想 “应该怎么做”
观察 AbstractMachine 程序编译过程的正确方法:
make -nB \
| grep -ve '^\(\#\|echo\|mkdir\|make\)' \
| sed "s#$AM_HOME#\$AM_HOME#g" \
| sed "s#$PWD#.#g" \
| vim -
make -nB
(RTFM)想要看得更清楚一些?
:%s/ /\r /g
编译
-std=gnu11
, m64
, -mno-sse
, -I
, -D
, ... (这对你配置 vscode 很重要)链接
-melf_x86_64
, -N
, -Ttext-segment=0x00100000
am-x86_64-qemu.a
, klib-x86_64-qemu.a
)彩蛋
make html
512 字节中的代码,假设了镜像格式 (真正的的加载器有很多 stages)
代码讲解:
am/src/x86/qemu/boot/start.S
和 main.c
if (elf32->e_machine == EM_X86_64) {
((void(*)())(uint32_t)elf64->e_entry)();
} else {
((void(*)())(uint32_t)elf32->e_entry)();
}
本次课回答的问题
Take-away message