一个操作系统的实现读书笔记

环境搭建

centos6.2(不推荐)

bochs  

> ./configure --anable-debugger --enable-disasm

nasm 推荐用RadAsm搭建环境,用vim也可以

保护模式

描述符属性

TYPE 值 数据段和代码段描述符 系统段和门描述符
0 只读 <未定义>
1 只读,已访问 可用286TSS
2 读/写 LDT
3 读/写,已访问 忙的286TSS
4 只读,向下扩展 286调用门
5 只读,向下扩展,已访问 任务门
6 读/写,向下扩展 286中断门
7 读/写,向下扩展,已访问 286陷阱门
8 只执行 <未定义>
9 只执行、已访问 可用386TSS
A 执行/读 <未定义>
B 执行/读、已访问 忙的386TSS
C 只执行、一致码段 386调用门
D 只执行、一致码段、已访问 <未定义>
E 执行/读、一致码段 386中断门
F 执行/读、一致码段、已访问 386陷阱门

一致的意思是这样的,当转 移的目标是一个特权级更高的一致代码段,当前的特权级会被延续下去,而 向特权级更高的非一致代码段的转移会引起常规保护错误(general-protection exception, #GP),除非使用调用门或者任务门。如果系统代码不访问受保护的 资源和某些类型的异常处理(比如,除法错误或溢出铕误),它可以被放在一 致代码段中。为避免低特权级的程序访问而被保护起来的系统代码则应放到非 一致代码段中。
要注意的是,如果目标代码的特权级低的话,无论它是不是一致代码段, 都不能通过cal 1或者jmp转移进去,尝试这样的转移将会导致常规保护错误。
所有的数据段都是非一致的,这意味着不可能被低特权级的代码访问到。 然而,与代码段不同的是,数据段可以被更高特权级的代码访问到,而不需要 使用特定的门。
总之,通过call和jmp的转移遵从表3.3所示的规则。

表 3.3 —S

 

 

特权级

低-离

特权级

髙—低

相同特权 级之间

适用于何种代码

-致代码段

Yes

No

Yes

不访问受保护的资源和某些 类型的异常处理的系统代码

非一致代码段

No

No

Yes

避免低特权级的程序访问而 被保护起来的系统代码

数据段

(总是非一致)

No

Yes

Yes

 


jap dword SelectorCode32 :0

前期准备GDT 32位代码段 16位代码段 跳回地址

;其正逬入保护棋式
jmp dword SelectorCode32 :0

处理器通过识别CPL、DPL、RPL这3种特权级进行特权级检验。
1. CPL (Current Privilege Level)
CPL是当前执行的程序或任务的特权级。它被存储在cs和ss的第0位和 第1位上。在通常情况下,CPL等于代码所在的段的特权级^当程序转移 到不同特权级的代码段时,处理器将改变CPL。
在遇到一致代码段时,情况稍稍有点特殊,一致代码段可以被相同或者更 低特权级的代码访问。当处理盔访问一个与CPL特权级不同的一致代码 段时,CPL不会被改变。
2. DPL (Descriptor Privilege Level)
DPL表示段或者门的特权级。它被存储在段描述符或者门描述符的DPL 字段中,正如我们先前所看到的那样。当当前代码段试图访问一个段或者 门时,DPL将会和CPL以及段或门选择子的RPL相比较,根据段或者门 类型的不同,DPL将会被区别对待,下面介绍一下各种类型的段或者门的 情况。
数据段:DPL规定了可以访问此段的最低特权级。比如,一个数据 段的DPL是1,那么只有运行在CPL为0或者I的程序才有权访问 它。
非一致代码段(不使用调用门的情况下):DPL规定访问此段的特权
级。比如,一个非一致代码段的特权级为0,那么只有CPL为0的程 序才可以访问它。
调用门:DPL规定了当前执行的程序或任务可以访问此调用门的最 低特权级(这与数据段的规则是一致的)。
—致代码段和通过调用门访问的非一致代码段:DPL规定了访问此
段的最高特权级。比如,一个一致代码段的DPL是2,那么CPL为0 和1的程序将无法访问此段。
TSS: DPL规定了可以访问此TSS的最低特权级(这与数据段的规 则是一致的h
3. RPL (Requested Privilege Level)
RPL是通过段选择子的第0位和第1位表现出来的。处理器通过检査RPL 和CPL来确认一个访问请求是否合法。即便提出访问请求的段有足够的 特权级,如果RPL不够也是不行的。也就是说,如果RPL的数字比CPL 大(数字越大特权级越低),那么RPL将会起决定性作用,反之亦然。 操作系统过程往往用RPL来避免低特权级应用程序访问高特权级段内的 数据。当操作系统过程(被调用过程)从一个应用程序(调用过程)接收 到一个选择子时,将会把选择子的RPL设成调用者的特权级。于是,当操 作系统用这个选择子去访问相应的段时,处理器将会用调用过程的特权级 (已经被存到RPL中),而不是更高的操作系统过程的特权级(CPL)进行 特权检验。这样,RPL就保证了操作系统不会越俎代庖地代表一个程序去 访问一个段,除非这个程序本身是有权限的。


不同特权级代码段之间的转移
程序从一个代码段转移到另一个代W段之前,目标代码段的选择子会被加 栽到cs中。作为加载过程的一部分,处理器将会检査描述符的界限、类型、特 权级等内容。如果检验成功,CS将被加载,程序控制将转移到新的代码段中, 从eip指示的位置开始执行。
程序控制转移的发生,可以是由指令jmp、call、ret、sysenter、 sysexit、int n或iret引起的,也可以由中断和异常机制引起。
使用jmp或call指令可以实现下列4种转移:
1.目标操作数包含目标代码段的段选择子。
2-目标操作数指向一个包含目标代码段选择子的调用门描述符。
3. 目标操作数指向一个包含目标代码段选择子的TSS。
4. 目标操作数指向一个任务门,这个任务门指向一个包含目标代码段选择子
的 TSS。
这4种方式可以看做是两大类,一类是通过jmp和call的直接转移(上述 第1种),另一类是通过某个描述符的间接转移(上述第2、3、4种)。下面就来
分别看一下。

特权级跳转

1. 根据目标代码段的DPL (新的CPL)从TSS中选择应'该切换至哪个ss和 esp
2- 从TSS中读取新的ss和esp。在这过程中如果发现ss、esp或者TSS界限 错误都会导致无效TSS异啬(#TS)o
3- 对日3描述符进行检验,如果发生错误,同样产4#TS异常。
4- 暂时性地保存当前ss和esp的值。
5.加载新的ss和esp。
6-将刚刚保存起来的ss和esp的值压入新栈。 
7. 从调用者堆栈中将参数复制到被调用者堆栈(新堆栈)中,复制参数的数 目由调用门中Param Count—项来决定。如果Param Count是零的话,将 不会复制参数。
8. 将当前的cs和eip压栈。
9. 加载调用门中指定的新的cs和eip,开始执行被调用者过程。
在第7步中,我们终于明白了调用门中Param Count的作用,至此,调用门 中各个部分的作用不再留有疑问。要说明的是,Param Count只有5位,也就是 说,最多只能复制31个参数。如果参数多于31个该怎么办呢?这时可以让其 中的某个参数变成指向一个数据结构的指针,或者通过保存在新堆栈里的ss 和esp来访问旧堆栈中的参数。
好了,此刻如果你结合图3.20和上述步骤,一定可以理解通过调用门进行 由外层到内层调用的全过程。那么,正如call指令对应ret,调用门也面临返 回的问题。通过图3.15和图3.16、图3.17和图3.18这两组对比,我们发现,ret基 本上是call的反过程,只是带参数的ret指令会同时释放事先被压栈的参数。
实际上,ret这个指令不仅可以实现短返回和长返回,而且可以实现带有 特权级变换的长返回。由被调用者到调用者的返回过程中,处理器的工作包含 以下步骤:
1. 检査保存的cs中的RPL以判断返回时是否要变换特权级。
2. 加载被调用者堆桟上的cs和eip (此时会进行代码段描述符和选择子类型 和特权级检验)。
3. 如果ret指令含有参数,则增加esp的值以跳过参数,然后esp将指向被 保存过的调用者ss和esp。注意,ret的参数必须对应调用门中的Param Count的值。
4. 加载ss和esp,切换到调用者堆栈,被调用者的ss和esp被丢弃。在这里 将会进行ss描述符、esp以及ss段描述符的检验。
5. 如果ret指令含有参数,增加esp的值以跳过参数(此时已经在调用者堆 栈中)•
6-检査ds、es、fs、gs的值,如果其中哪一个寄存器指向的段的DPL小于 CPL (此规则不适用于一致代码段),那么一个空描述符会被加载到该寄 存器。


boot载入loader loader加载kernel复制GDT


ELF文件格式

内核雏形

C和汇编混用

global和extern用法

添加终端处理

增加软中断号,给系统调用中断添加终端号,建立系统调用表,分配系统调用

建立进程,(进程表)进程控制块,存放进程寄存器信息,内核到ring3的跳转,TTS的使用

进程总数的限制,任务的实现,进程的调度,时钟中断的使用


输入输出的实现

读取键盘输入的驱动,tty的实现,与用户的交互


进程间通信

通过消息的机制,微内核的原理及实现


文件系统

磁盘驱动的实现,文件系统的设计 文件的读写


内存管理

fork的实现,动态进程的创建和执行,shell的实现



;其正逬jp dword SelectorCode32 :0;其正逬入保护棋式
jap dword SelectorCode32 :0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对x86架构的处理器,业界一向是褒贬不一。但是毫无疑问的是,x86架构的处理器是迄今为止在市场上最成功的处理器。它既催生了Intel、微软这样的业界巨头,也改变了普通人们的生活。到今天,虽然有arm的异军突起,但是大部分程序员所编写的程序依然在运行在x86架构上。 虽然很多上层的程序员绕过了对CPU架构本身的理解,而直接使用高级语言进行编程,但是对CPU本身的熟悉,其实依然是所有想被称为优秀的程序员所难以绕过的一道坎。对CPU的不熟悉,实际上限制了程序员的思维方式、对程序的理解和实际解决问题的能力。 对于普通的芯片,阅读几页的说明书就可以大致理解如何让它工作。CPU是比较复杂的一种,对于比较简单的CPU架构,阅读几十页的文档也能大致熟悉。然而 x86架构的CPU的说明可不是这么简单,其手册估计有一共有四、五千页之巨。不要说理解透彻,就是从头到尾翻一遍也不是一件简单的事情。并非Intel 有意将它做得复杂,这里有历史的原因。因为这个架构的应用实在太广了,全世界有无数的软件都在它的基础之上工作。为此它自身的升级也就变得举步维艰。每次升级都不得不要兼容之前的特性。这也就导致了新旧指令层层堆积,种种特性互相兼顾,最终变成如今的一团乱麻了。 对于入门级的选手,读完那些手册可不是一件容易的事情。但是于渊的这本《orange's:一个操作系统实现》却是一条难得的终南捷径。因为要理解如何让一个芯片正常工作,最简单的办法就是从头开始去写程序让它运行起来,然后操作它做自己想做的事情。如果是平时的编程,这些下层的工作都已经有操作系统帮你做了,对理解x86架构的帮助就大为有限。如果去读那几千页的文档,不但读起来很痛苦,中间又没有多少可以实际操作的工作来帮助你温故而知新,这其中的枯燥乏味,绝对不是一般人可以忍受的了。而且更重要的手册中虽然包含了x86所有的特性,然而其中有些特性是现代操作系统根本就没有用到的。努力的去理解的话,又是吃力不讨好了。如果每个读者都可以随着这本书的介绍,去逐步的实现一个操作系统,不但这中间其乐无穷,而且实现到最后,对x86架构的理解也就不在话下。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值