系列文章目录
文章目录
- 系列文章目录
- 前言
- 九、操作系统状态机模型(系统加载)
- 软件和硬件的桥梁
- 操作系统状态机模型
- 十、状态机模型的应用
- 查看状态机执行
- 总结
前言
九、操作系统状态机模型(系统加载)
- 软件和硬件的桥梁
- 操作系统的加载和初始化
- AbstractMachine代码导读
__
LabOS
- 熟悉代码框架
- 多处理器上的kalloc/free
- 中断和异常驱动的上下文(线程)切换
- 虚拟地址空间、用户态进程和系统调用
- 虚拟文件系统。devfs, procfs, 简单的文件系统;ELF加载器
如果一个人在未经训练的情况下就能把某件事情做的很好,证明他在某件事情上很有“天赋”,但是和接受过专业训练的人依然存在不小的差距。
--------------
“专业世界观”的学习方法(没啥,paper都发不了):
- 经典研究论文(OSDI, SOSP, ATC, EuroSys, …)
- 久经考验的经典教学材料(xv6, OSTEP, CSAPP, …)
- 海量的开源工具(GNU系列,qemu, gdb, …)
- 第三方资料,慎用(tutorials, osdev wiki, … 可能这些不能保证100%准确)
软件和硬件的桥梁
参考单片机在按下reset后cpu从某个固定的位置开始执行命令。
电路reset后cpu寄存器有个初始状态(具体值需要查阅厂家手册),从一个固定地址开始执行命令。只需要在这个地上写入命令就可以了。
- CPU reset后,处理器处于某个确定的状态
- PC指针一般指向一段memory-mapped ROM
- ROM存储了厂商提供的firmware(固件)
- 处理器的大部分特性处于关闭状态
- 缓存、虚拟存储、…
- PC指针一般指向一段memory-mapped ROM
- Firmware(固件,厂商提供的代码)
- 将用户数据加载到内存
- 例如存储介质上的第二级loader(加载器)
- 或者直接加载操作系统(嵌入式系统)
- 将用户数据加载到内存
cpu reset 后:
- 从PC(CS : IP)指针处取指令、译码、执行…
- 从firmware开始执行。FFFF0通常是一条指向firmware跳转的指令
Firmware: BIOS vs. UEFI
- 都是主板/主板上外插设备的软件抽象
- 支持系统管理程序运行
- Legacy BIOS (Basic I/O System)
- UEFI (Unified Extensible Firmware Interface)
- firmware是由硬件厂商提供的软件,称为 固件
- Legacy BIOS 把第一个可引导设备的第一个扇区加载到物理内存的7c00位置
- 此时处理器处于16-bit模式
- 规定CS:IP = 0x7c00
- 其他没有任何约束
- 将启动磁盘前512字节的数据加载到内存对应位置(0x7c00),如果最后两个字节为AA55则认为是启动磁盘
- Legacy BIOS 把第一个可引导设备的第一个扇区加载到物理内存的7c00位置
- 它负责将硬盘中固定位置的代码段搬到内存中7c00的位置,然后这段代码再执行其他操作(内存中7c00代码就是磁盘前512字节的内容,由BIOS加载)然后这段代码相当于boot loader把OS的代码搬运到内存(实际上有多级加载器)
模拟CPUreset调试方案:QEMU
Firmware的另一用处:
- 放置一些“绝对安全的代码”
- BIOS中断(字符的打印)
- ARM Trusted Firmware
- Boot-Level 1,2,3.1,
- U-Boot: the universal boot loader
今天的Firmware:UEFI
操作系统状态机模型
Firmware和boot loader共同完成“操作系统的加载”
- 初始化全局变量和栈;分配heap
- 为main函数传递参数
AbstractMachine API
十、状态机模型的应用
编译器:源代码S(状态机) -> 二进制码U(状态机)
C = compile(S)
现代CPU:
instruction-level parallelism
在一个时钟周期内执行不止一条、乱序的执行,只要保证最终状态相同即可
IPC>1,每个时钟周期执行多条指令
#include <stdio.h>
#include <time.h>const unsigned long LOOP = 1000000000ul;__attribute__((noinline)) void loop()
{for (long i = 0; i < LOOP; ++i) {asm volatile("mov $1, %%rax;""mov $1, %%rdi;""mov $1, %%rsi;""mov $1, %%rdx;""mov $1, %%rcx;""mov $1, %%r10;""mov $1, %%r8;""mov $1, %%r9;":::"rax", "rdi", "rsi", "rdx", "rcx", "r10", "r8", "r9");}
}int main()
{clock_t st = clock();loop();clock_t ed = clock();double inst = LOOP * (8 + 2) / 1000000000;double ips = inst / ((ed - st) * 1.0 / CLOCKS_PER_SEC);printf("%.2lfG instructions/s\n", ips); // CPU:
}
g++ -O2 IPC.cpp
查看状态机执行
工具:strace/gdb
调试器应该具有:记录状态、在状态之间跳转等功能
记录程序的行为:
指令+结果
操作系统状态机需要记录IO, 中断,即可完整的重放整个操作系统的执行。
观察和记录完整的状态机执行。
在低代价下得到程序执行的summary
Premature optimization is the root of all evil.
**strace -t ** 查看系统调用花费的时间。
每隔一段时间查看状态机的状态,如何实现? 中断
性能摘要需要对程序执行性能影响最小,往往不需要full trace。
隔一段时间“暂停”程序、观察状态机的执行
- 中断就可以做到
- 将状态s->s’ “记录”
- 执行的语句
- 函数调用栈
- 服务的请求
- 得到统计意义的性能摘要
profiler工具:
- perf list, perf stat (-e), perf record, perf report
总结
没有总结,占个坑位