[0] 操作系统学习 (一些奇奇怪怪的问题)

·

4 min read

查看本系列文章目录

下列内容可能有出错的地方, 毕竟只是个人理解, 有问题评论区🥲🥲

这篇文章将会讲述一些, 你可能以前听过的但又不了解的问题, 作为开始学习 OS 的铺垫

操作系统是什么?

...在盘古开天之际,除动物以外,世界上只有土地、荒草、树木、石头等资源。人 们为了躲避天灾、野兽攻击等危险,开始住进了山洞,为了获取食物,用石头和树木等材料打造一些武器。 当时所有人都在做这些相同的事 。 这就是没有组织的人类社会,所有人都在重复“造轮子”。 后来各个地区有了自己权威性的部落,部落都专门找人打造武器,谁需要武器就直接申请领取便可, 大部分人不需要自己打造武器了 。 后来嫌打猎太麻烦了,干脆养一些家畜好了,直接供给人们,谁需要可 以过来交换。这就是把大家的重复性劳动集中到了一起,让人们可以专注于自己的事情。 再后来,部落之间为了通信,开始有信使了,这是最原始的通信方式。到后来发展到有社会组织,通 信越来越频繁了,干脆搞个驿站吧,谁需要通信 ,直接写信,由驿站代为送达。 随着人口越来越多,社会组织需要了解到底有多少人,为了方便人口管理,于是就在各地建了“户籍 办事”处,人们的生老病死都要到那里登记申报。

上面提到的部落其实就是最原始的操作系统雏形 -- 操作系统真象还原

软件是怎么访问硬件?

大家都知道硬件的更新速度很快, 种类增加得也很快. 例如:今年 RTX3800 显卡发售了

OS 开发者不可能花费大量时间来编写这些硬件的驱动. 于是乎, 便出现了各种硬件适配设备, 这就是 IO 接口. 接口其实就是标准, 大家生产出来的硬件按照这个标准工作就实现了通用。

硬件在输入和输出上大体分为串行和并行

  • 串行 : 硬件通过串行接口向 CPU 通讯
  • 并行 : CPU 通过并行接口同硬件通讯

那么要怎么访问硬件呢?

1 通过内存映射

把一个 外设的内存 映射到 电脑的一定范围的内存, 当 CPU 访问这一范围的内存时, 就像访问了 外设的内存

例如 : 显卡 大家都知道显卡有一个东西叫 显存, 这个显存被 CPU 映射到电脑的一定内存范围中(如:主机物理内存上的低端 1MB 的0xB8000~0xBFFFF), CPU写入这一内存范围就是写入显存, 往这片内存上写字节便是往屏幕上打印内容

2 通过 IO 接口

外设和 CPU 通过 IO 接口 通讯,访问 IO 接口的本质就是访问寄存器(后边会讲,可理解为内存), 这些寄存器就是人们常说的端口

应用程序和操作系统的关系

应用程序和操作系统其实都是一坨代码, 不过操作系统更底层, 权利也更大, 而软件要依靠操作系统才能生活

1.png

应用程序通过系统提供的应用接口(API)来实现某项功能

例如在 C 语言中, 我们使用编译器(如 GCC)通过的库(运行库 Runtime Library)来实现一些功能

库函数中又有封装的系统调用,这样的代码集合称之为运行库。 C语言的 运行库称为 C 运行库,就是所谓的 CRT ( C Runtime Library)。 -- 操作系统真象还原

应用程序加上操作系统提供功能才算是完整的程序。由于有了操作系统的支持,一些现成的东西己经摆 在那了,但这些是属于操作系统的,不是应用程序的,所以咱们平时所写的应用程序只是半成品,需要调用 操作系统提供好的函数才能完整地做成一件事,而这个函数便是系统调用。 -- 操作系统真象还原

例如一个简单的例子:打印文字

#include <stdio.h>

int main()
{
    printf("hello world");
    return 0;
}

这里通过运行库 stdio.h 里的 printf 函数向屏幕输出 hello world

什么是 '陷入' 内核?

当发生中断时, 应用程序被暂时终止执行, 并把应用程序的上下文(什么是上下文呢? 我也不知道, 估计是应用程序的使用内存, 和一下状态)保存起来, 然后运行一段内核代码

如果把软件分层的话, 最外圈是应用程序,里面是操作系统,如图所示 。 应用程序处于特权级 3,操作系统内核处于特权级 0。当用户程序欲 访问系统资源时(无论是硬件,还是内核数据结构),它需要进行系统调 用。这样 CPU 便进入了内核态,也称管态 。 看图中凹下去的部分,是不 是有陆进去的感觉,这就是“陷入内核” 。 --操作系统真象还原

2.png

简单说一下寄存器

我们先简单讲一下寄存器, 后面会详细讲

简单的说寄存器就是访问速度比内存更快的东西, 它存在于 CPU 中, 而不是主板上, 大小我们也无法随便改

以前的寄存器都是 16位宽(2 的 16 次方,64KB)的, 不过现在科技的进步, 已经出现了 32 位, 64 位的 CPU 了 寄存器也是有许多种的, 可以分为:如图

8.png

内存访问为什么要分段?

在说段之前我们应该先看看内存长什么样, 内存像一条带子,内存地址按顺序从低到高排列

内存是随机读写设备,即访问其内部任何 一 处,不需要从头开始找,只要直接 给出其地址便可 。 如访问内存 0xc00,只要将此地址写入地址总线便可 。 --操作系统真象还原

3.png

这主要有 2 个原因

1 为了重定向

大家都知道物理内存的绝对地址都是独一无二的, 所以没办法 2 个以上的程序访问相同的内存地址

例如

QQ 想往 0xc00 这个地址写入 1

而微信也想往 0xc00 写入 2

这样 当 QQ 重新访问 0xc00 时, 就是 2 不是 1

这样不就乱套了吗?

所以从 8086 (一款 intel 的 CPU) 开始就采用了 分段的方式访问内存, 这样 CPU 就可以将程序访问内存进行 重定向, 程序访问的内存地址也从绝对地址变成了相对地址

5.png

2 为了访问到更多内存地址

我们知道以前 CPU(如 8086)的寄存器都是16 位宽, 所以只能访问 64KB(0~0xFFFF) 的内存地址, 但是大家见过 64KB 的内存条吗? 现在随随便便都有 4GB 了吧, 不过现在我们还不讲 4GB 怎么访问?看完下文之后读者可以自己思考一下😜

我们先将一下 1MB 的内存怎么访问

16 位的寄存器最多访问到 64KB大小的内存。虽然 lMB 内存中可容纳 lMB/64KB= 16 个最大段,但 这只是可以容纳而己,并不是说可以访问到。 16 位的寄存器超过 0xFFFF后将会回卷到 0,又从 0 重新开始。 20 位宽度的内存地址空间必然只能由 20 位宽度的地址来访问。问题又来了,在当时只有 16 位寄存器的 情况下是如何做到访问 20位地址空间的呢? --操作系统真象还原

CPU 的设计者很早就意识到了这个问题, 他们在地址处理单元中搞了个奇奇怪怪的操作

地址处理单元在接到 CPU 的 段基址+段内偏移地址 后,先将段基址乘以 16(0x10)(即左移 4 位), 然后在和 16 位的段内偏移地址相加,这下地址就变成 20 位了

假设我要访问0xffff0 -> 随便取一个偏移:0xffff+0x12 -> 0xffff * 0x10 + 0x12 -> 0xffff0

这样我们就可以访问 1MB 的内存了

还有就是访问更大内存的问题(如 4GB),这个问题随着32,64 位 CPU 的出现而解决了

32位CPU只能访问3.25GB的内存

64位CPU可以访问128GB内存 (应该没人有 128GB 内存吧😅)

可能保护模式下的分页功能也有关系

为什么地址有这么多奇奇怪怪叫法?😩🔨

物理地址

就是我们上面讲的未分段前的地址, 就是绝对的, 整个内存只有一个

CPU 最终都是以物理地址访问内存

在实模式下,“段基址+段内偏移地址”经过段部件的处理,直接输出的就是物理地址, CPU 可以直接用此地址访问内存 。

线性地址

这个我也不知道怎么说, 就直接引用<<操作系统真象还原>>的话

在保护模式下,"段基址+段内偏移地址”称为线性地址,不过,此时的段基址已经不再是真正的地址 了,而是一个称为选择子的东西 。 它本质是个索引,类似于数组下标,通过这个索引便能在 GDT 中找到相应 的段描述符,在该描述符中记录了该段的起始、大小等信息,这样便得到了段基址。若没有开启地址分页功能, 此线性地址就被当作物理地址来用,可直接访问内存。 若开启了分页功能,此线性地址又多了一个名字,就是 虚拟地址 (虚拟地址、线性地址在分页机制下都是一回事)。 虚拟地址要经过 CPU 页部件转换成具体的物理地 址,这样 CPU 才能将其送上地址总线去访问内存 。 --操作系统真象还原

有效地址

就是'段基址+段内偏移地址'中的 段内偏移地址

虚拟地址

这都不是真实的内存地址。它们都用来描述程序或任务的地址空间 。 由于 分页功能是需要在保护模式下开启的, 32 位系统保护模式下的寻址空间是 4GB,所以虚拟地址或线性地 址就是0~4GB的范围。 转换过程如图所示。 --操作系统真象还原

6.png

段重叠, 什么鬼?

其实这个很简单

假设我们要访问 0xc03

段基址可以是0xc00~0xc03, 这样段偏移可以是 0x03~0x00

但是如果段基址 A:0xc00 B:0xc02

所以他们都可以访问 0xc05这个内存, 所以段就重叠了

7.png

字节序

分类:

  1. 小端字节序是数值的低宇节放在内存的低地址处,数值的高宇节放在内存的高地址。
  2. 大端字节序是数值的低宇节放在内存的高地址处,数值的高宇节放在内存的低地址。

优势:

  1. 小端:因为低位在低宇节,强制转换数据型时不需要再调整宇节了。
  2. 大端:有符号数,其宇节最高位不仅表示数值本身,还起到了符号的作用。符号位固定为第 一字 节,也就是最高位占据最低地址,符号直接可以取出来,容易判断正负。

常见 CPU 的字节序:

  1. 大端字节序: IBM、 Sun、 PowerPC。
  2. 小端字节序: x86、 DEC。

关于字节序就介绍到这里, 因为我觉得可能没什么用所以就没怎么讲, 知道个大概就行🤪 [狗头保命]

什么是中断?

在计算机中, 从内部发出的事件就为异常. 从外部发出的事件就为中断.

如:

  • CPU 计算 1*0 时, 发现 0 不能做除数, 就抛出了异常, 以处理这个事件
  • 当 U盘接入电脑时, CPU 就产生了中断, 来处理U盘的事件

BIOS 中断

BIOS(基本输入/输出系统)的创建是为了向早期的PC系统程序员提供通用的低级服务。基本目标是:从操作系统和应用程序中隐藏(尽可能)PC模型和硬件的变化,并使操作系统和应用程序开发更容易(因为BIOS服务处理了大多数硬件级接口)。 --OSDev

BIOS运行期间就会扫描0xc0000~0xe0000(外设内存映射的范围, 上面有讲), 如果它发现某个区域开头是 0x55, 0xaa, 就进行一些奇奇怪怪的操作(具体步骤可 Google) 然后把它加入中断向量表(IVT), 这样即可给自己调用, 或者是其他程序使用(如:boot,loader)

BIOS 中断的调用是通过写入AH 寄存器和 int 实现的(如 int 0x13)

常见功能:

  • INT 0x10 INT 0x10,AH = 1——设置光标 INT 0x10,AH = 3——光标位置 INT 0x10,AH = 0xE -- 显示字符 INT 0x10,AH = 0xF——获取视频页面和模式 INT 0x10,AH = 0x11 -- 设置8x8字体 INT 0x10,AH = 0x12 -- 检测 EGA/VGA INT 0x10,AH = 0x13 -- 显示字符串 INT 0x10,AH = 0x1200 -- 备用打印屏幕 INT 0x10,AH = 0x1201 -- 关闭光标模拟 INT 0x10,AX = 0x4F00 -- 显存大小 INT 0x10,AX = 0x4F01 -- VESA 获取模式信息调用 INT 0x10,AX = 0x4F02 -- 选择VESA视频模式 INT 0x10,AX = 0x4F0A -- VESA 2.0 保护模式接口
  • INT 0x11 -- 硬件检测 INT 0x13,AH = 0 --重置软盘/硬盘 INT 0x13,AH = 2--在CHS模式下读取软盘/硬盘 INT 0x13,AH = 3--以CHS模式写入软盘/硬盘 INT 0x13,AH = 0x15 -- 检测第二磁盘 INT 0x13,AH = 0x41——测试INT 13扩展的存在性 INT 0x13,AH = 0x42——以LBA模式读取硬盘 INT 0x13,AH = 0x43——以LBA模式写入硬盘
  • INT 0x12——获得低内存大小 INT 0x15,EAX = 0xE820--获取完整的内存映射 INT 0x15,AX = 0xE801——获取连续内存大小 INT 0x15,AX = 0xE881 -- 获取连续内存大小 INT 0x15,AH = 0x88 -- 获取连续内存大小
  • INT 0x15 INT 0x15,AH = 0xC0 -- 检测 MCA 总线 INT 0x15,AX = 0x0530 -- 检测 APM BIOS INT 0x15,AH = 0x5300 -- APM检测 INT 0x15,AX = 0x5303 -- APM使用32位连接 INT 0x15,AX = 0x5304 -- APM断开连接
  • INT 0x16 INT 0x16,AH = 0--读取键盘扫描码(阻塞) INT 0x16,AH = 1--读取键盘扫描码(非阻塞) INT 0x16,AH = 3-键盘重复率

DOS 中断

DOS 是运行在实模式下的,故其建立的中断调用也建立在中断向量表中,只不过其中断向量号和 BIOS 的不能冲突 。 Ox20~Ox27 是 DOS 中断 。因为 DOS 在实模式下运行,故其可以调用 BIOS 中断 。 DOS 中断只占用 Ox21 这个中断 号,也就是 DOS 只有这一个中断例程。 DOS 中断调用中那么多功能是如何实现的?是通过先往 ah 寄存器中写好子功能号,再执行 int Ox21。 这时在中断向 量表 中第 Ox21 个表项,即物理地址 Ox21*4 处中的中断处理程序开始根据寄存器 ah 中的值 来调用相应的子功能。 --操作系统真象还原

MBR, EBR, DBR, OBR 是什么?

其实很简单, 大家看一下我自己搞的一张流程图就可以明白

4.png

补充: 64 字节大小的分区表,里面是分区信息。分区 表中每个分区表项占 16 字节,因此 MBR 分区表中可容纳 4 个分区,这 4 个分区就是“次引导程序”的 候选人群, MBR 引导程序开始遍历这 4个分区,想找到合适的人选并把系统控制权交给他。 --操作系统真象还原

下一个:操作系统开发环境搭建