Operating System
$Nanjing\ University\rightarrow Yanyan\ Jiang\newline$
Overview
复习
本次课回答的问题
Q : 听说操作系统也是程序。那到底是鸡生蛋还是蛋生鸡?
本次课主要内容
软件和硬件的桥梁
操作系统的加载和初始化
AbstractMachine 代码导读
自己动手写操作系统
时事热评
小学生写了三个月的操作系统是什么样的?
本学期的 OSLabs
热身实验
正经实验
Lab1 (pmm): Physical memory management
多处理器 (bare-metal) 上的 kalloc/free
Lab2 (kmt): Kernel multi-threading
Lab3 (uproc): User processes
Lab4 (vfs): Virtual file system
devfs, procfs, 简单的文件系统;ELF 加载器
大学的真正意义
将已有的知识和方法重新消化,为大家建立好 “台阶”,在有限的时间里迅速赶上数十年来建立起的学科体系
例子
“专业世界观” 的学习方法
经典研究论文 (OSDI, SOSP, ATC, EuroSys, …)
久经考验的经典教学材料 (xv6, OSTEP, CSAPP, …)
海量的开源工具 (GNU 系列, qemu, gdb, …)
第三方资料,慎用 (tutorials, osdev wiki, …)
硬件和软件的桥梁
C 程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <sys/syscall.h>
. globl _start
_start :
movq $ SYS_write , % rax // write(
movq $ 1 , % rdi // fd=1,
movq $ st , % rsi // buf=st,
movq $ ( ed - st ), % rdx // count=ed-st
syscall // );
movq $ SYS_exit , % rax // exit(
movq $ 1 , % rdi // status=1
syscall // );
st :
. ascii " \033 [01;31mHello, OS World \033 [0m \n "
ed :
“程序 = 状态机” 没问题
带来更多的疑问
但谁创建的这个状态机???
这个程序可以在没有操作系统的硬件上运行吗?
“启动” 状态机是由 “加载器” 完成的
加载器也是一段程序 (状态机)
这个程序由是由谁加载的?
1
2
3
┌──( kali㉿kali) -[ ~/chapter9]
└─$ file minimal
minimal: ELF 64-bit LSB executable, x86-64, version 1 ( SYSV) , statically linked, not stripped
CPU reset 后,处理器处于某个确定的状态
PC 指针 一般指向一段 memory-mapped ROM
ROM 存储了厂商提供的 firmware (固件)
处理器的大部分特性处于关闭状态
Firmware (固件,厂商提供的代码)
将用户数据加载到内存
例如存储介质上的第二级 loader (加载器)
或者直接加载操作系统 (嵌入式系统)
x86 Family: CPU Reset 行为
friendly manual
让qemu
模拟器停在第一条指令上,和上面的手册对照,会发现和手册一致
CPU Reset 之后:发生了什么?
BIOS
Legacy BIOS: 约定
Firmware 必须提供机制,将用户数据载入内存
Legacy BIOS 把第一个可引导设备的第一个扇区加载到物理内存的 7c00
位置 ,这也是我们Fireware和OS之间的第一次,也是唯一一次握手
Windows启动模式:老的Windows的A,B盘都是软盘,BIOS先去软盘里面读前512个bytes
,看最后两个byte是否为55aa
(大端),如果是就加载这块磁盘,否则读下一块,如果都不是就启动失败。读完A/B盘之后引导到C盘,这也是为什么今天的Windows操作系统C盘是系统盘的原因
Firmware做的事情(以BIOS为例)
能不能看一下代码?
Talk is cheap. Show me the code. ——Linus Torvalds
ffmpeg
调试 QEMU: 确认 Firmware 的行为
亲眼确认 Firmware 到底是不是会加载启动盘第一个扇区到 0x7c00
内存位置!
调试 QEMU 模拟器
查看 CPU Reset 后的寄存器
查看0x7c00
内存的加载
watch *0x7c00
- 《计算机系统基础》的良苦用心
查看当前指令 x/i ($cs * 16 + $rip)
打印内存 x/16xb 0x7c00
进入0x7c00
代码的执行
b *0x7c00
, c
(撒花!我们一会再回来)
鸡和蛋的问题解决
有个原始的鸡:Firmware
代码直接存在于硬件里
CPU Reset 后 Firmware 会执行
加载 512 字节到内存 (Legacy Boot)
Firmware 的另一用处
放置一些 “绝对安全的代码”
BIOS 中断 (Hello World 是如何被打印的)
如果加载失败将错误信息打印出来
ARM Trusted Firmware
Boot-Level 1, 2, 3.1, 3.2, 3.3
U-Boot : the universal boot loader
小插曲:Firmware 的病毒 (1998)
CIH 的作者陈盈豪被逮捕,但并未被定罪
病毒代码结尾的CIH
今天的 Firmware: UEFI
UEFI
UEFI 上的操作系统加载
标准化的加载流程
盘必须按 GPT (GUID Partition Table) 方式格式化
预留一个 FAT32 分区 (lsblk/fdisk 可以看到)
Firmware 加载任意大小的 PE 可执行文件.efi
没有 legacy boot 512 字节限制
EFI 应用可以返回 firmware
更好的程序支持
操作系统的状态机模型
“操作系统” 的状态机已经启动
Firmware 和 boot loader 共同完成 “操作系统的加载”
初始化全局变量和栈;分配堆区 (heap
)
为 main
函数传递参数
操作系统:是个 C 程序
一个迷你 “操作系统” thread-os.c
make 会得到一个 “磁盘镜像”,好像魔法一样
就跟你们第一次用 IDE 的时候按一个键就可以编译运行一样
1
2
3
4
5
6
7
8
9
10
11
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 );
}
thread-os.c
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
#define MAX_CPU 8
typedef union task {
struct {
const char * name ;
union task * next ;
void ( * entry )( void * );
Context * context ;
};
uint8_t stack [ 8192 ];
} Task ;
Task * currents [ MAX_CPU ];
#define current currents[cpu_current()]
// user-defined tasks
int locked = 0 ;
void lock () { while ( atomic_xchg ( & locked , 1 )); }
void unlock () { atomic_xchg ( & locked , 0 ); }
void func ( void * arg ) {
while ( 1 ) {
lock ();
printf ( "Thread-%s on CPU #%d \n " , arg , cpu_current ());
unlock ();
for ( int volatile i = 0 ; i < 100000 ; i ++ ) ;
}
}
Task tasks [] = {
{ . name = "A" , . entry = func },
{ . name = "B" , . entry = func },
{ . name = "C" , . entry = func },
{ . name = "D" , . entry = func },
{ . name = "E" , . entry = func },
};
// ------------------
Context * on_interrupt ( Event ev , Context * ctx ) {
extern Task tasks [];
if ( ! current ) current = & tasks [ 0 ];
else current -> context = ctx ;
do {
current = current -> next ;
} while (( current - tasks ) % cpu_count () != cpu_current ());
return current -> context ;
}
void mp_entry () {
iset ( true );
yield ();
}
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 );
}
AbstractMachine 对 “C 程序语义” 做出的扩充
CTE
允许创建多个执行流 (类比协程) - M2
yield 主动切换;会被中断被动打断
on_interrupt
会拦截到中断事件
VME
允许创建一个 “经过地址翻译的执行模式”
通过 CTE API 管理
有关中断代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Context * on_interrupt ( Event ev , Context * ctx ) {
extern Task tasks [];
if ( ! current ) current = & tasks [ 0 ];
else current -> context = ctx ;
do {
current = current -> next ;
} while (( current - tasks ) % cpu_count () != cpu_current ());
return current -> context ;
}
void mp_entry () {
iset ( true );
yield ();
}
1
2
3
4
5
6
void iset ( bool enable ) {
extern sigset_t __am_intr_sigmask ;
// NOTE: sigprocmask does not supported in multithreading
int ret = sigprocmask ( enable ? SIG_UNBLOCK : SIG_BLOCK , & __am_intr_sigmask , NULL );
assert ( ret == 0 );
}
RTFSC 时间
(0) 生成镜像和启动虚拟机
如果使用 “土办法”,你很可能被淹没在 Makefile 中
读懂 Makefile 需要 STFW, RTFM,大量的精力
虽然花点时间读是值得的,但很可能读了很久都没读到重要的地方
Abstract-Machine 通过脚本+重定向可以转化为HTML代码 进行阅读
1
2
3
4
┌──( jungle㉿jungle-virtual-machine) -[ ~/deom1/abstract-machine]
└─$ sudo apt install python3-markdown
┌──( jungle㉿jungle-virtual-machine) -[ ~/deom1/abstract-machine]
└─$ cat Makefile | sed 's/^\([^#]\)/ \1/g' | markdown_py > Makefile.html
注:使用了自动化工具python3-markdown
(0) 生成镜像和启动虚拟机 (cont’d)
观察 AbstractMachine 程序编译过程的正确方法:
1
2
3
4
5
make -nB \
| grep -ve '^\(\#\|echo\|mkdir\|make\)' \
| sed "s# $AM_HOME #\$AM_HOME#g" \
| sed "s# $PWD #.#g" \
| vim -
Command line tricks
make -nB
(RTFM)
grep: 文本过滤,省略了一些干扰项
echo (提示信息), mkdir (目录建立), make (sub-goals)
sed: 让输出更易读
vim: 更舒适的编辑/查看体验
部分make -nB
的输出信息
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Building hello-image [x86_64-qemu]
mkdir -p /home/jungle/deom1/deom/build/x86_64-qemu/ && echo + CC main.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/deom/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/deom/build/x86_64-qemu/main.o /home/jungle/deom1/deom/main.c
mkdir -p /home/jungle/deom1/deom/build/x86_64-qemu/ && echo + CC say.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/deom/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/deom/build/x86_64-qemu/say.o /home/jungle/deom1/deom/say.c
make -s -C /home/jungle/deom1/deom/../abstract-machine/am archive
# Building am-archive [x86_64-qemu]
mkdir -p /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/ && echo + AS src/x86/qemu/start64.S
x86_64-linux-gnu-gcc -MMD -I/home/jungle/deom1/deom/../abstract-machine/am/src -I/home/jungle/deom1/abstract-machine/am/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -m64 -fPIC -c -o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/start64.o /home/jungle/deom1/abstract-machine/am/src/x86/qemu/start64.S
mkdir -p /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/ && echo + AS src/x86/qemu/trap64.S
x86_64-linux-gnu-gcc -MMD -I/home/jungle/deom1/deom/../abstract-machine/am/src -I/home/jungle/deom1/abstract-machine/am/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -m64 -fPIC -c -o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/trap64.o /home/jungle/deom1/abstract-machine/am/src/x86/qemu/trap64.S
mkdir -p /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/ && echo + CC src/x86/qemu/trm.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/deom/../abstract-machine/am/src -I/home/jungle/deom1/abstract-machine/am/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/trm.o /home/jungle/deom1/abstract-machine/am/src/x86/qemu/trm.c
mkdir -p /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/ && echo + CC src/x86/qemu/cte.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/deom/../abstract-machine/am/src -I/home/jungle/deom1/abstract-machine/am/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/cte.o /home/jungle/deom1/abstract-machine/am/src/x86/qemu/cte.c
mkdir -p /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/ && echo + CC src/x86/qemu/ioe.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/deom/../abstract-machine/am/src -I/home/jungle/deom1/abstract-machine/am/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/ioe.o /home/jungle/deom1/abstract-machine/am/src/x86/qemu/ioe.c
mkdir -p /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/ && echo + CC src/x86/qemu/vme.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/deom/../abstract-machine/am/src -I/home/jungle/deom1/abstract-machine/am/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/vme.o /home/jungle/deom1/abstract-machine/am/src/x86/qemu/vme.c
mkdir -p /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/ && echo + CC src/x86/qemu/mpe.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/deom/../abstract-machine/am/src -I/home/jungle/deom1/abstract-machine/am/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/mpe.o /home/jungle/deom1/abstract-machine/am/src/x86/qemu/mpe.c
echo + AR "->" build/am-x86_64-qemu.a
ar rcs /home/jungle/deom1/abstract-machine/am/build/am-x86_64-qemu.a /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/start64.o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/trap64.o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/trm.o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/cte.o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/ioe.o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/vme.o /home/jungle/deom1/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/mpe.o
make -s -C /home/jungle/deom1/deom/../abstract-machine/klib archive
# Building klib-archive [x86_64-qemu]
mkdir -p /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/ && echo + CC src/stdio.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/abstract-machine/klib/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/stdio.o /home/jungle/deom1/abstract-machine/klib/src/stdio.c
mkdir -p /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/ && echo + CC src/int64.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/abstract-machine/klib/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/int64.o /home/jungle/deom1/abstract-machine/klib/src/int64.c
mkdir -p /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/ && echo + CC src/string.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/abstract-machine/klib/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/string.o /home/jungle/deom1/abstract-machine/klib/src/string.c
mkdir -p /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/ && echo + CC src/cpp.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/abstract-machine/klib/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/cpp.o /home/jungle/deom1/abstract-machine/klib/src/cpp.c
mkdir -p /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/ && echo + CC src/stdlib.c
x86_64-linux-gnu-gcc -std=gnu11 -O2 -MMD -Wall -Werror -I/home/jungle/deom1/abstract-machine/klib/include -I/home/jungle/deom1/deom/../abstract-machine/am/include/ -I/home/jungle/deom1/deom/../abstract-machine/klib/include/ -D__ISA__=\"x86_64\" -D__ISA_X86_64__ -D__ARCH__=x86_64-qemu -D__ARCH_X86_64_QEMU -D__PLATFORM__=qemu -D__PLATFORM_QEMU -DARCH_H=\"arch/x86_64-qemu.h\" -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector -Wno-main -U_FORTIFY_SOURCE -m64 -fPIC -mno-sse -c -o /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/stdlib.o /home/jungle/deom1/abstract-machine/klib/src/stdlib.c
echo + AR "->" build/klib-x86_64-qemu.a
ar rcs /home/jungle/deom1/abstract-machine/klib/build/klib-x86_64-qemu.a /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/stdio.o /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/int64.o /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/string.o /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/cpp.o /home/jungle/deom1/abstract-machine/klib/build/x86_64-qemu/src/stdlib.o
echo + LD "->" build/hello-x86_64-qemu.elf
x86_64-linux-gnu-ld -melf_x86_64 -N -Ttext-segment=0x00100000 -o /home/jungle/deom1/deom/build/hello-x86_64-qemu.elf --start-group /home/jungle/deom1/deom/build/x86_64-qemu/main.o /home/jungle/deom1/deom/build/x86_64-qemu/say.o /home/jungle/deom1/deom/../abstract-machine/am/build/am-x86_64-qemu.a /home/jungle/deom1/deom/../abstract-machine/klib/build/klib-x86_64-qemu.a --end-group
echo \# Creating image [x86_64-qemu]
make -s -C /home/jungle/deom1/deom/../abstract-machine/am/src/x86/qemu/boot
echo + CC start.S main.c
x86_64-linux-gnu-gcc -static -m32 -fno-pic -Os -nostdlib -Ttext 0x7c00 -I/home/jungle/deom1/deom/../abstract-machine/am/src -o bootblock.o start.S main.c
python3 genboot.py bootblock.o
echo + CREATE "->" build/hello-x86_64-qemu
( cat /home/jungle/deom1/deom/../abstract-machine/am/src/x86/qemu/boot/bootblock.o; head -c 1024 /dev/zero; cat /home/jungle/deom1/deom/build/hello-x86_64-qemu.elf ) > /home/jungle/deom1/deom/build/hello-x86_64-qemu
(0) 生成镜像和启动虚拟机 (cont’d)
想要看得更清楚一些?
编译
-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
)
彩蛋
(1) 启动加载器 (Boot Loader)
512 字节中的代码,假设了镜像格式 (真正的的加载器有很多 stages)
16-bit → 32-bit
ELF32/64 的加载器
代码讲解:
am/src/x86/qemu/boot/start.S
和main.c
1
2
3
4
5
if ( elf32 -> e_machine == EM_X86_64 ) {
(( void ( * )())( uint32_t ) elf64 -> e_entry )();
} else {
(( void ( * )())( uint32_t ) elf32 -> e_entry )();
}
总结
本次课回答的问题
Take-away message
一切皆可调试 (包括 firmware)
理解操作系统是如何被启动的
学会使用 gdb (必备生存技能)
操作系统也是程序
AbstractMachine 扩展了程序的语义,仅此而已
声明:本文章引用资料与图像均已做标注,如有侵权本人会马上删除