【日拱一卒行而不辍20220922】自制操作系统

GDTR

写GDTR有一个专用的指令:LGDT。

该指令在实模式和保护模式下都可以执行,用这条指令就可以成功定位GDT在内存中的位置。

到这里,我们访问32位地址的内存就没有障碍了,方法是把寄存器GDTR和表GDT的内容分别设置好,就能通过操控16位段寄存器(CS,DS,ES,SS,FS,GS)来实现目标。

整个流程控制都是由CPU实现的,这种控制模式就叫保护模式。

一旦进入保护模式,16位的段寄存器(CS,DS,ES,SS,FS,GS)的数据结构定义就将发生变化:

不再是实模式下的具体段地址了,而是一个带有“索引”的逻辑地址,通过这个索引值到GDT中寻找32位的内存起始地址。这时候,这些段寄存器就有了一个新的称呼:段选择子

我们要访问任何内存数据,就必须首先定义好这个段选择子。

jmp dword 0x0008:inprotectmode是在实模式下编译的,它是切换到保护模式唯一方式。

dword字段的含义是指定跳转之后的偏移地址要用32位来定义,也即会将inprotectmode的偏移地址装入EIP。

jmp到0x0008的含义是:CS=0x0008,这里就务必要注意,这个时候因为已经打开了保护模式,那么CS就不再是段地址的含义了,而是保护模式下的含义,它代表的是要将段选择子数据设置成0x0008

堆栈区

保护模式下的堆栈区是否正常工作:这是一个非常重要的地方,关系到32位系统能否正常启动运行。

因为,如果你没有特别注意堆栈区的设置,很可能使用PUSH和POP指令的时候,会把数据写到代码区或者数据区了。在进入32保护模式后,我们要做的第一件事其实就应该是设置SS和ESP的值

为何不能直接用C编译生成的代码运行?

C语言编译生成的目标代码是ELF格式的,不是机器代码序列,直接加载无法运行。

需要将所需机器代码从C语言编译后的目标文件(obj)里抽取出来。

这里就有一个很重要的问题:指令INC DWORD [EAX] 是直接对内存进行寻址操作,内存直接寻址默认的寄存器应该是DS,所以这个数据访问寻址实际上是:DS:-4+EBP(LEA指令的作用是取偏移地址,这里LEA EAX,DWORD [-4+EBP]实际上等效于mov eax,-4+EBP,只不过nasm语法要求必须要加[])。EBP最开始的时候取自于ESP,ESP取决于我们的系统设置,在我的系统中我设置的是0x00007c00。所以,变量i的绝对地址:-4+EBP=0x00007bfc。那么现在我们要用DS:-4+EBP访问0x00007bfc必须要确保DS=0才行!故为了C语言编译后的程序能在我们的系统中正常运行,就必须要在进入保护模式之后在GDT中把DS段描述符的线性基地址映射成0x00000000。否则,C语言程序就无法集成到你的系统中。

任务切换

任务切换最核心的地方就是要保证这些CPU在每次重新运行的时候,都必须要保持和上一次一模一样的状态。为此,这3个CPU就可以理解为一个临时的CPU状态暂存区,用它来存储每个任务退出的时候真正CPU的最新状态,而下次重新运行该任务时,只需要从这个逻辑CPU装载状态到真正的CPU即可。那么如何定义一个CPU的状态呢?其实很简单,它就是所有和程序运行有关的寄存器集合。包括:通用寄存器、专用寄存器、段寄存器、状态寄存器等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值