NJUOS-9-操作系统的状态机模型

本文最后更新于:2 年前

并发的内容,包括Debug的,在这里就已经全部够啦!!!可以做点小的习题+Model Checker看看代码执行的过程,接下来回到操作系统,继续学习!!!

大学&“专业”

大学的意义:将已有的知识和方法重新消化,为大家建立好 “台阶”,在有限的时间里迅速赶上数十年来建立起的学科体系。

  • 操作系统真的就是个 C 程序
  • 你只是需要 “被正确告知” 一些额外的知识
    • 然后写代码、吃苦头
    • 从而建立正确的 “专业世界观”

专业的素质:

“专业世界观” 的例子 (这些都没啥,paper 都发不了)

  • 写 x86 模拟器的时候,不知道哪条指令错了,怎么办?
  • 做操作系统实验的时候,如果遇到神秘 CPU Reset,怎么办?
  • 做实验做不下去的时候,该实现什么工具?

“专业世界观” 的学习方法

  • 经典研究论文 (OSDI, SOSP, ATC, EuroSys, …)
  • 久经考验的经典教学材料 (xv6, OSTEP, CSAPP, …)
  • 海量的开源工具 (GNU 系列, qemu, gdb, …)
  • 第三方资料,慎用 (tutorials, osdev wiki, …)

如果难顶,可能还要自己写一点工具,能够帮助我们解决对应的问题(聪明的,有效率的)

操作系统的启动

我们已经知道如何写一个 “最小” 的 C 程序了:

  • minimal.S
  • 不需要链接任何库,就能在操作系统上运行

“程序 = 状态机” 没问题

  • 带来更多的疑问
    • 但谁创建的这个状态机???
      • 当然是操作系统了……呃……
    • 这个程序可以在没有操作系统的硬件上运行吗?
      • “启动” 状态机是由 “加载器” 完成的
      • 加载器也是一段程序 (状态机)
      • 这个程序由是由谁加载的?

egg or chicken first?

  • Bare-metal 与程序员的约定(硬件和软件之间的约定!)

    • 为了让计算机能运行任何我们的程序,一定存在软件/硬件的约定。比如按下了CPU的电源,发生了什么。

    • CPU reset 后,处理器处于某个确定的状态(约定好的,固定的状态)-> 硬件厂商固定了硬件初始设置和一些固定的启动代码,然后固定开始执行(例如扫描外设)。这才有了操作系统的启动。

      • PC 指针一般指向一段 memory-mapped ROM
        • ROM 存储了厂商提供的 firmware (固件)
      • 处理器的大部分特性处于关闭状态
        • 缓存、虚拟存储、……
    • Firmware (固件,厂商提供的代码)

      • 将用户数据加载到内存
        • 例如存储介质上的第二级 loader (加载器)
        • 或者直接加载操作系统 (嵌入式系统)

In computing, firmware is a specific class of computer software that provides the low-level control for a device’s specific hardware. Firmware, such as the BIOS of a personal computer, may contain basic functions of a device, and may provide hardware abstraction services to higher-level software such as operating systems.

image-20221219165030140

image-20221219165115334

  • Legacy BIOS: 约定
    • Firmware(硬件上写死的那些东西) 必须提供机制,将用户数据载入内存
    • Legacy BIOS 把第一个可引导设备的第一个扇区加载到物理内存的 7c00 位置
      • 此时处理器处于 16-bit 模式
      • 规定 CS:IP = 0x7c00, (R[CS] << 4) | R[IP] == 0x7c00
        • 可能性1:CS = 0x07c0, IP = 0
        • 可能性2:CS = 0, IP = 0x7c00
      • 其他没有任何约束

操作系统和Firmware(Legacy Bios)的约定是:启动磁盘的第一个512个字节,叫主引导扇区(Master Boot Record, MBR)。512个字节,由firmware帮助我们自动搬到内存中的某个固定位置,并且开始执行。

上面就是我们的操作系统和Firmware的第一次,也是唯一一次握手。

  • 怎么表示,一个磁盘的前512个字节是可以启动的?

image-20221219170552365

为啥Windows从C盘开始编号?因为A, B盘是软盘,会从软盘驱动器读出对应的内容,看看能不能启动昂!

  • BIOS: 内存的7C00,存储的是磁盘的前512个字节,PC也指向这个位置。 -> BIOS就是帮助把代码搬过来,然后执行,开始拉起操作系统。

能不能看一下代码?

image-20221219170957293

qemu给了gdb接口,我们可以在gdb中调试,这样就相当于给操作系统一个watchpoint,可以一步一步的看昂!!!

Gdb -x bootloader.gdb -> -x可以预先执行一些脚本,这样可以做很多初始化的配置昂!

image-20221220101440666

鸡和蛋的问题解决(Firmware)

有个原始的鸡: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
  • 笑死ROM可写!!!植入病毒!!!

image-20221220101842072

ROM给你更新了,在ROM里面写入了一个死循环??? -> 开机都开不了。。。这个ROM没有写保护,可以更新,就造成了firmware并植入了病毒昂!!!

image-20221220104642943

image-20221220111854094

操作系统的状态机模型

Firmware 和 boot loader 共同完成 “操作系统的加载”

  • 初始化全局变量和栈;分配堆区 (heap)
  • 为main函数传递参数
    • 谁给操作系统传递了参数?
    • 如何实现参数传递?

进入 C 代码之后

  • 完全遵循 C 语言的形式语义
  • 但有一些行为 “补充” —— AbstractMachine API

一个迷你 “操作系统” 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);
}

你怎么写一个操作系统?要知道并理解各个API的作用:

image-20221220113233352

例如:

  • 上面的mpe_init:将一个单线程的C程序,变成一个多线程的C程序。
  • cpu_count():获得CPU的数量

mp_entry就是创建了cpu_count()个线程,每个线程都只有一个调用栈的栈帧。就是mp_entry,没有参数,PC就在代码的最头上。然后在CPU上执行调用就行

并发,多进程的状态机 -> 就是多进程处理器!!!

  • 状态机是真的强啊。。。

所有的并发 + 系统调用(虚拟内存的翻译,中断),都可以在状态机中进行表示,本质就是状态机的转换!!!

上面这些API,就是状态机正确流转的最小的API啊!!!无非就是实现一个状态机嘛!!!

image-20221220114739036

  • 就上面这幅图,从BIOS, bootloader, main, mpe_init, CPU多线程执行,开中断之类的。从计算机一开始到最后多线程运行,本质就是一整个状态机的轮转哇!!!
  • 例如CPU1开中断之后。变成了CPU1执行,CPU1中断和CPU2执行三条路径,状态机分叉增加,中断后面又跟着中断响应的处理,比如把CPU1的线程状态存入全局Context,然后改变指针指向去执行别的!!!
  • GDB调试代码,本质上就是走了上面这幅图中的一根线!!!你跟着代码动态的,从状态机上走了一次。
  • 这里可以看看原视频,讲的非常的好!!!1h 15min左右昂!!!

RTFSC时间

GDB调试代码,本质上就是走了上面这幅图中的一根线!!!你跟着代码动态的,从状态机上走了一次。正确阅读代码,就应该顺着状态机走一次,理解一次,停下来看看情况!!!而不是一味干读代码昂!!!

image-20221220115504542

例如代码上有注释,注释不就是#,诶嘿!这个不就是markdown里面,不同的标题记号吗?输出成Markdown,不就可以方便的根据注释作为标题,来主动找代码逻辑吗?

image-20221220115711164

过滤一些杂七杂八的内容!!! -> 而且,空格换成换行也很酷!!!

image-20221220115805346

代码一下就清楚了昂!!!

用命令行,都是在编程(上面这种替换,就可以用正则表达式!!!)

  • 老师刚刚给的那个例子,就可以调试,建议看看原视频。看看make是如何编译的!!!就和按一下Clion的按键一样,怎么一下子就跑起来了??? -> blackbox就会给人失控的感觉!
  • 可以看看,我们是怎么去make,构造磁盘镜像过程的昂!!!

image-20221220120300128

image-20221220120311682

References

  1. 这个视频前几分钟特有意思,笑死我了,小学生 pk 大学生:https://www.bilibili.com/video/BV1yP4y1M7FE/?spm_id_from=333.999.0.0&vd_source=ff957cd8fbaeb55d52afc75fbcc87dfd

image-20221219163126499

小学生很强orz

  1. 课件在这里:http://jyywiki.cn/OS/2022/slides/9.slides#/

NJUOS-9-操作系统的状态机模型
https://alexanderliu-creator.github.io/2022/12/19/njuos-9-cao-zuo-xi-tong-de-zhuang-tai-ji-mo-xing/
作者
Alexander Liu
发布于
2022年12月19日
许可协议