进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3

这里写目录标题

前言

有了王道考研操作系统的整体概念框架,下面就开始更深层次的学习了——李治军老师的操作系统

这一步接近实操,算是实操的理论指导,我目前不会进行实操,经过对一二章内容的实操,我发现对我来说还是太难了,我想通过课程先建立一个更细的框架。

因为一步有一步的难点,刚开始我直接看的李,看到第二章就看不下去,不懂的太多了,现在把王看完后,今天早上又看了李,发现大部分都能理解了。
有时候就像你不戴眼镜后听力也会下降一样,你几个知识点不懂就会导致整个视频看的都是晕晕乎乎的。

最后就是上手实践操作了,想理论实践齐头并进的同学可以自己试试。
8个小实验平台是shiyanlou:https://www.shiyanlou.com/courses/115
注册一下就可以进行线上实验了,实验内容和视频里讲的基本一样

好像还有四个大实验,我还没有了解,之后再说

L1 什么是操作系统

建议2倍速观看

L2 揭开钢琴的盖子

实模式和保护模式都是CPU的工作模式,而CPU的工作模式是指CPU的寻址方式、寄存器大小等用来反应CPU在该环境下如何工作的概念。
实模式下,物理地址 = 段基址<<4 + 段内偏移,即 PC=CS≪4+IP
为什么这样计算,请参考https://zhuanlan.zhihu.com/p/42309472
CS:IP(CS≪4+IP)

上电后,计算机做的第一件事,肯定是根据 **最最初始的PC值**,找到要执行的第一条指令,然后往下执行指令。
上电后, 80x86结构的CPU将自动进入实模式,所以这个 **最最初始的PC值** = 最最初始的CS≪4 + 最最初始的IP。而最最初始的 CS=0xFFFF,IP=0x0000 是由硬件设计者用电路初始化的。

BIOS并不是放在内存中的,而是放在ROM(只读存储器).而BIOS由硬件来加载,被加载到 0xF0000~0xFFFFF处.
参考https://blog.csdn.net/qq_43701555/article/details/109510087
BIOS是存储在ROM里面的,不用调入内存就可直接被CPU运行.
https://blog.csdn.net/linuxheik/article/details/7669585
BIOS 运行初期,CPU 其实是不能访问内存的。BIOS 所在的 FLASH 是那种可以被 CPU 直接寻址的 FLASH 芯片。
https://blog.csdn.net/wwl33695/article/details/8433035

找到的第一条指令的地址是PC=CS≪4+IP=0xFFFF0,这个地方是 BIOS(Basic Input Output System,基本输入输出系统),这里的代码会测试基本硬件,同时提供了一些让用户调用硬件基本输入/输出功能的子程序。

BIOS会读取硬盘的第一个扇区(0扇区),内含512个字节。这些数据叫做主引导记录(Master Boot Record简称MBR)。
一般说来,它包含两个极其重要的部分:一个是位于MBR开头的操作系统相关的引导程序,另一个是紧跟其后的磁盘分区表。
BIOS 丝毫不关心这些事情:它只是简单的加载MBR的内容到内存地址0x7C00处,并跳转到此处开始执行,不管MBR里的代码是什么。
参考https://blog.csdn.net/pyf09/article/details/96285386

如果硬件测试正常,就利用 BIOS 的输入功能将启动磁盘的启动扇区(磁盘0磁道0扇区)的512字节的内容读入到内存的 0x7C00 地址处,并设置寄存器 CS=0x07C0,IP=0x0000,跳转到这个地方开始引导启动机器运行

引导扇区代码:bootsect.s (512字节)
核心代码如下:
BOOTSEG = 0x07C0
INITSEG = 0x9000
mov ax,#BOOTSEG
mov ds,ax // ds = ax = BOOTSEG = 0x07C0 段寄存器
mov ax,#INITSEG
mov es,ax // es = ax = INITSEG = 0x9000 段寄存器
mov cx,#256 //cx = 256
sub si,si //si=0 段内偏移
sub di,di //di=0 段内偏移
rep // REP(重复)
movw //mov 移动 w字(对应两个字节)

以上代码功能:将内存中开始地址为 DS:SI = 0x7C00 的 256 个字移动到开始地址为 ES:DI = 0x90000 的地方。

jmpi go,INITSEG //jmpi 段间跳转 段寄存器ip = go 段内偏移cs = INITSEG

以上代码功能:设置 CS 寄存器为 INITSEG = 0x9000,IP 寄存器为标号 go(从 bootsect.s 的第一条语句到“go”指向语句的偏移字节数),显然就是设置 PC=0x90000+go

go: · · · · · · // go标号
load_setup:· · · · · · // 载入setup模块
//中间通过 中断int 0x13 读磁盘扇区
进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3

ok_load_setup:· · · · · · // 载入setup模块
进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3

call read_it //读入system模块
为什么要定义一个函数?因为system模块可能很大,要跨越磁道
jmpi 0,SETUPSEG//转入setup执行
ip=0 cs=SETUPSEG=0x9020

以上bootsect.s核心代码实现:
1.将自己移动到内存绝对地址 0x90000 开始处并继续执行。(为读入操作系统核心代码腾出空间)
2.把从磁盘第 2 个扇区开始的 4 个扇区的 setup 模块(由 setup.s 编译而成)加载到内存紧接着 bootsect 后面(0x90200),然后利用 BIOS 中断 0x13 取磁盘参数表中当前启动引导盘的参数,接着在屏幕上显示字符串。
3.把磁盘上 setup 模块后面的system 模块加载到内存 0x10000 开始的地方。
4.转入setup执行

L3 操作系统启动

计算机刚上电的时候,操作系统在磁盘上,要把操作系统读入到内存里,才能取指执行。由引导扇区代码(bootsect.s)完成。
bootsect.s先读入setup,然后打印logo,再把操作系统后面的system模块读入。
setup模块,由setup.s编译得来,完成OS启动前的设置

进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3
1.获得各种硬件参数
2. setup 程序将 system 模块从 0x10000-0x8ffff 整块向下移动到内存绝对地址 0x00000 处
(实际上将 system 从 0x10000 挪到 0x0地址处,BIOS 中断就没法使用了,因为 BIOS 中断向量表就放置在 0 地址处)
进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3
3.初始化gdt表(为了执行“jmpi 0,8”而临时建立的)
最上面的将setup移到0地址处,个人感觉应该是打错了,应该是将system移到0地址处
进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3
4.进入保护模式,跳到system模块执行

(16位 -> 32位)进入保护模式,寻址方式改变

mov ax,#0x0001 mov cr0,ax //cr0 32位寄存器,第0位为1时,启动保护模式
jmpi 0,8 // ip=0 cs=8,保护模式下,根据cs查gdt表+ip = 0,跳到**system模块**执行

全局描述符表(GDT)
保护模式下,虽然段值仍然由原来的cs、ds等寄存器表示,但此时它仅仅变成了一个索引,这个索引指向了一个数据结构的一个表项,表项中详细定义了段的起始地址、界限、属性等内容。这个数据结构就是全局描述符GDT
https://www.cnblogs.com/chenwb89/p/operating_system_002.html

cs - 选择子 :查表的索引
段的基址放在表项中
进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3

进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3

段基址31-24:00 c0 9a 段基址23-16:00
段基址15-8:00 段基址7-0:00 07 ff

段基址连起来就是0x00000000

system模块(目标代码)中的第一部分代码:head.s
system由许多文件编译而成,为什么是head.s?

操作系统 控制代码Makefile:

makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具
原文链接:https://blog.csdn.net/haoel/article/details/2886/

操作系统镜像Image 文件
进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3
我好晕,个人理解,仅供参考,欢迎讨论,感谢指点!

把这一部分捋一下:最开始上电后,BIOS检测硬件后,将磁盘的引导扇区bootsect模块读入到内存的 0x7C00,
运行bootsect.s,将自己移动到内存 0x90000,将setup模块加载到内存紧接着 bootsect 后面(0x90200),然后把磁盘上 setup 模块后面的system 模块加载到内存 0x10000,
转入setup执行,将 system 模块从 0x10000移动到内存 0x00000 处,进入保护模式,
跳到system模块执行。
以上是计算机的启动过程,三个模块在内存中的位置必须是如图所示的。
我们的电脑基于硬件有一套操作系统,之后可以通过虚拟机映像文件使用别的操作系统。
这个映像文件Image是由操作系统 控制代码Makefile编译来的,它的样子也要和图示一样,就是通过Makefile定义的一些规则来保证的

同时system模块由许多文件编译而成,怎么保证第一个是head.s也是通过Makefile来保证的

head.s 程序在被编译生成目标文件后会与内核其他程序的目标文件一起被链接成 system 模块,并位于 system 模块的最前面开始部分。这也就是为什么称其为头部(head)程序的原因。system 模块将被放置在磁盘上 setup 模块之后开始的扇区中,即从磁盘上第 6 个扇区开始放置。

heads.s 汇编程序与前面汇编的语法格式不同,它采用的是 AT&T 的汇编语言格式,代码中赋值的方向是从左到右。
进一步学习操作系统 - 哈工大李治军老师 - 学习笔记 L1L2L3

system开始的第一个文件是head.s,存放在地址0处,因此setup结束后执行的就是head.s文件。
在head.s里面会重新设置idt表、gdt表、还会开启A20地址线(je 1b),开启A20地址线之后寻址范围就是4G而不再是1M。
head.s(汇编) —》main.c(C函数)和c语言里面的函数调用是一样的,首先将函数执行完之后的下一个地址和函数参数压入栈中,然后通过jmp命令跳到子函数的执行处,执行完了之后再利用ret跳到程序原来执行的地方。

参考https://blog.csdn.net/www_dong/article/details/115637262

上一篇:python故障排查


下一篇:Vue3.0 的新特征 | Vue3.0 面试题总结