一个操作系统的实现:关于保护模式和实模式的跳转和段描述符高速缓冲寄存器

本文探讨了在实模式和保护模式之间进行切换的具体方法,包括如何正确地使用跳转指令来实现不同位模式间的转换,并详细解释了为何在从保护模式返回实模式时必须通过16位代码段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.cnblogs.com/pang123hui/archive/2010/11/27/2309926.html

   依旧是第三章,看的好慢哦,其实从实模式跳转到保护模式还是很好懂得,主要注意就是跳转指令:

 

jmp dword SelectorCode32:0  
//而不能是  
jmp SelectorCode32:0  



     因为这时编译出来的是16位代码。如果目标地址的偏移不是0,而是一个较大的值,比如:

 

jmp SelectorCode32:0x12345678  



则编译后偏移会被截断,只剩下0x5678。

 

     所以,这个特殊的跳转需要特殊的处理。在Linux内核中(Linux使用的是AT&T汇编,不是一般常见的IBMPC汇编),这个跳转是用DB指令直接写二进制代码的方法实现的,而NASM显然提供了更好的解决方法,就是加一个dword,本来dword应该加在偏移之前,但NASM允许加在整个地址之前,就像我们之前做的那样,这也是NASM的优点吧。总之 一个程序中可以包含多个不同位的段,32位或者16位,他们之间也可以互相跳转,只是32位段用的是32位寄存器,16位代码段用的是16位寄存器,如果要在16位段下使用32位寄存器,必须象高级语言中强制类型转换一样,显示的定义 dword。

 

     而从保护模式跳转回实模式则不是那么好理解了,至少我是这样认为的,因为在准备结束保护模式回到实模式之前,需要加载一个合适的描述符选择子到有关的段寄存器,以使对应段描述符高速缓冲寄存器(见后面的解释)中含有合适的段界限和属性(这里正确的段界限显然是64K,即0ffffh,属性应该是DA_DRW,即90h可读写数据段),而且,不能从32位代码段返回实模式,只能从16位代码段中返回。这是因为无法实现从32位代码段返回时cs高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)。

 

     在实模式下,段寄存器含有段值,为访问存储器形成物理地址时,处理器引用相应的某个段寄存器并将其值乘以16,形成20位的段基地址。在保护模式下,段寄存器含有段选择子,如上所述,为了访问存储器形成线性地址时,处理器要使用选择子所指定的描述符中的基地址等信息。为了避免在每次存储器访问时,都要访问描述符表而获得对应的段描述符,从80286开始每个段寄存器都配有一个高速缓冲寄存器,称之为段描述符高速缓冲寄存器或描述符投影寄存器,对程序员而言它是不可见的。每当把一个选择子装入到某个段寄存器时,处理器自动从描述符表中取出相应的描述符,把描述符中的信息保存到对应的高速缓冲寄存器中。此后对该段访问时,处理器都使用对应高速缓冲寄存器中的描述符信息,而不用再从描述符表中取描述符。

     新增的Normal描述符,段界限64K,属性DA_DRW,在返回实模式之前把对应选择子SelectorNormal加载到ds、es和ss正好合适。

### 保护模式概述 保护模式是一种现代处理器的工作状态,在这种状态下,CPU 可以更高效地管理内存资源并提供多任务支持。通过分页机制段描述符表,保护模式允许操作系统更好地控制内存访问权限以及地址空间隔离[^1]。 在 Bochs 模拟环境中开发操作系统保护模式切换过程中,可能会遇到一些常见的问题及其对应的解决方法如下: --- ### 常见问题及解决方案 #### 问题一:Bochs 调试环境下无法跳转至自定义主引导扇区 此问题是由于 BIOS 初始化完成后未能正确加载用户的主引导记录 (MBR),从而导致调试停留在 BIOS 阶段。 **解决方案**: 修改 Bochs 的配置文件 `bochsrc.txt` 中的硬盘映像路径设置,确保其指向正确的虚拟磁盘镜像文件,并启用日志记录以便排查错误原因[^3]。 ```bash ATAPI_CDROM_IMAGE: file="path_to_your_cdrom.iso", status=inserted, type=cdrom ``` 上述代码片段展示了如何指定 CD-ROM 映像的位置参数。 --- #### 问题二:从模式切换到保护模式失败 通常情况下,这可能是由于 GDT(全局描述符表)未被正确定义或者加载不成功引起的。如果 CR0 寄存器中的 PE(Protection Enable)标志位没有开启,则 CPU 将继续处于模式下工作。 **解决方案**: 确认以下几点: - 正确初始化 GDTR(GDT Register); - 设置好相应的段选择子; - 更新 EIP/EFLAGS 寄存器值来完成际转换动作;最后再验证是否已真正进入了目标模式[^4]. 以下是用于创建简单的GDT结构体的一个例子: ```asm gdt_start: dq 0x0 ; null descriptor code_seg: dw 0xFFFF ; limit low dw 0x0 ; base low db 0x0 ; base middle db 10011010b ; access byte db 11001111b ; granularity db 0x0 ; base high data_seg equ $ - gdt_start lgdt [gdtr] mov eax , cr0 or al , 1 mov cr0 , eax ; enable protected mode by setting the first bit of cr0 register. jmp dword code_seg : start_protected_mode ``` 注意这里的汇编语法可能依据具体工具链有所差异. --- #### 问题三:返回模式时发生异常 当尝试从保护模式回到模式时,CS 缓冲寄存器内的属性不符合模式需求的情况会出现崩溃现象。这是因为某些旧版硬件不允许动态调整段特性所致。 **解决方案**: 设计合理的双态兼容逻辑,即先保存当前环境变量副本后再逐步退出复杂的状态直至基础级别恢复为止. 同时建议采用较新版本模拟平台减少此类架构局限带来的麻烦。 --- ### 总结 以上列举了几种典型的 bochs 平台下有关保护模式实现阶段可能出现的技术难点连同相应对策进行了阐述说明。希望这些信息能够帮助开发者顺利推进项目进展。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值