关于从保护模式切换到实模式的相关说明

参考于渊的《自己动手写操作系统》第三章中从实模式切换到保护模式,最后有重新切回实模式的代码(代码如下),其中有几点不太明白的,参考其他文章之后在此记录一下。

其中还有不太明白的地方,希望大家能在下面 留个言帮我讲明白,谢谢。

下面代码有些宏定义没贴出来,应该能看明白。

  1; ==========================================
  2; pmtest2.asm
  3; 编译方法:nasm pmtest2.asm -o pmtest2.com
  4; ==========================================
  5
  6%include    "pm.inc"    ; 常量, 宏, 以及一些说明
  7
  8org    0100h
  9    jmp    LABEL_BEGIN
 10
 11[SECTION .gdt]
 12; GDT
 13;                                         段基址,       段界限     , 属性
 14LABEL_GDT:        Descriptor           0,                 0, 0             ; 空描述符
 15LABEL_DESC_NORMAL:    Descriptor           0,            0ffffh, DA_DRW        ; ***注意此处为Normal 描述符*****
 16LABEL_DESC_CODE32:    Descriptor           0,  SegCode32Len - 1, DA_C + DA_32    ; 非一致代码段, 32
 17LABEL_DESC_CODE16:    Descriptor           0,            0ffffh, DA_C        ; 非一致代码段, 16
 18LABEL_DESC_DATA:    Descriptor           0,    DataLen - 1, DA_DRW        ; Data
 19LABEL_DESC_STACK:    Descriptor           0,        TopOfStack, DA_DRWA + DA_32    ; Stack, 32 位
 20LABEL_DESC_TEST:    Descriptor    0500000h,            0ffffh, DA_DRW
 21LABEL_DESC_VIDEO:    Descriptor     0B8000h,            0ffffh, DA_DRW        ; 显存首地址
 22; GDT 结束
 23
 24GdtLen        equ    $ - LABEL_GDT    ; GDT长度
 25GdtPtr        dw    GdtLen - 1    ; GDT界限
 26        dd    0        ; GDT基地址
 27
 28; GDT 选择子
 29SelectorNormal        equ    LABEL_DESC_NORMAL    - LABEL_GDT
 30SelectorCode32        equ    LABEL_DESC_CODE32    - LABEL_GDT
 31SelectorCode16        equ    LABEL_DESC_CODE16    - LABEL_GDT
 32SelectorData        equ    LABEL_DESC_DATA        - LABEL_GDT
 33SelectorStack        equ    LABEL_DESC_STACK    - LABEL_GDT
 34SelectorTest        equ    LABEL_DESC_TEST        - LABEL_GDT
 35SelectorVideo        equ    LABEL_DESC_VIDEO    - LABEL_GDT
 36; END of [SECTION .gdt]
 37
 38[SECTION .data1]     ; 数据段
 39ALIGN    32
 40[BITS    32]
 41LABEL_DATA:
 42SPValueInRealMode    dw    0
 43; 字符串
 44PMMessage:        db    "In Protect Mode now. ^-^", 0    ; 进入保护模式后显示此字符串
 45OffsetPMMessage        equ    PMMessage - $$
 46StrTest:        db    "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
 47OffsetStrTest        equ    StrTest - $$
 48DataLen            equ    $ - LABEL_DATA
 49; END of [SECTION .data1]
 50
 51
 52; 全局堆栈段
 53[SECTION .gs]
 54ALIGN    32
 55[BITS    32]
 56LABEL_STACK:
 57    times 512 db 0
 58
 59TopOfStack    equ    $ - LABEL_STACK - 1
 60
 61; END of [SECTION .gs]
 62
 63
 64[SECTION .s16]
 65[BITS    16]
 66LABEL_BEGIN:
 67    mov    ax, cs
 68    mov    ds, ax
 69    mov    es, ax
 70    mov    ss, ax
 71    mov    sp, 0100h
 72
 73    mov    [LABEL_GO_BACK_TO_REAL+3], ax
 74    mov    [SPValueInRealMode], sp
 75
 76    ; 初始化 16 位代码段描述符
 77    mov    ax, cs
 78    movzx    eax, ax
 79    shl    eax, 4
 80    add    eax, LABEL_SEG_CODE16
 81    mov    word [LABEL_DESC_CODE16 + 2], ax
 82    shr    eax, 16
 83    mov    byte [LABEL_DESC_CODE16 + 4], al
 84    mov    byte [LABEL_DESC_CODE16 + 7], ah
 85
 86    ; 初始化 32 位代码段描述符
 87    xor    eax, eax
 88    mov    ax, cs
 89    shl    eax, 4
 90    add    eax, LABEL_SEG_CODE32
 91    mov    word [LABEL_DESC_CODE32 + 2], ax
 92    shr    eax, 16
 93    mov    byte [LABEL_DESC_CODE32 + 4], al
 94    mov    byte [LABEL_DESC_CODE32 + 7], ah
 95
 96    ; 初始化数据段描述符
 97    xor    eax, eax
 98    mov    ax, ds
 99    shl    eax, 4
100    add    eax, LABEL_DATA
101    mov    word [LABEL_DESC_DATA + 2], ax
102    shr    eax, 16
103    mov    byte [LABEL_DESC_DATA + 4], al
104    mov    byte [LABEL_DESC_DATA + 7], ah
105
106    ; 初始化堆栈段描述符
107    xor    eax, eax
108    mov    ax, ds
109    shl    eax, 4
110    add    eax, LABEL_STACK
111    mov    word [LABEL_DESC_STACK + 2], ax
112    shr    eax, 16
113    mov    byte [LABEL_DESC_STACK + 4], al
114    mov    byte [LABEL_DESC_STACK + 7], ah
115
116    ; 为加载 GDTR 作准备
117    xor    eax, eax
118    mov    ax, ds
119    shl    eax, 4
120    add    eax, LABEL_GDT        ; eax <- gdt 基地址
121    mov    dword [GdtPtr + 2], eax    ; [GdtPtr + 2] <- gdt 基地址
122
123    ; 加载 GDTR
124    lgdt    [GdtPtr]
125
126    ; 关中断
127    cli
128
129    ; 打开地址线A20
130    in    al, 92h
131    or    al, 00000010b
132    out    92h, al
133
134    ; 准备切换到保护模式
135    mov    eax, cr0
136    or    eax, 1
137    mov    cr0, eax
138
139    ; 真正进入保护模式
140  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;在此由实模式切进保护模式;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
141    jmp    dword SelectorCode32:0    ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处
142
143;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
144
145LABEL_REAL_ENTRY:        ; 从保护模式跳回到实模式就到了这里
146    mov    ax, cs
147    mov    ds, ax
148    mov    es, ax
149    mov    ss, ax
150
151    mov    sp, [SPValueInRealMode]
152
153    in    al, 92h        ; ┓
154    and    al, 11111101b    ; ┣ 关闭 A20 地址线
155    out    92h, al        ; ┛
156
157    sti            ; 开中断
158
159    mov    ax, 4c00h    ; ┓
160    int    21h        ; ┛回到 DOS
161; END of [SECTION .s16]
162
163
164[SECTION .s32]; 32 位代码段. 由实模式跳入.
165[BITS    32]
166
167LABEL_SEG_CODE32:
168    mov    ax, SelectorData
169    mov    ds, ax            ; 数据段选择子
170    mov    ax, SelectorTest
171    mov    es, ax            ; 测试段选择子
172    mov    ax, SelectorVideo
173    mov    gs, ax            ; 视频段选择子
174
175    mov    ax, SelectorStack
176    mov    ss, ax            ; 堆栈段选择子
177
178    mov    esp, TopOfStack
179
180
181    ; 下面显示一个字符串
182    mov    ah, 0Ch            ; 0000: 黑底    1100: 红字
183    xor    esi, esi
184    xor    edi, edi
185    mov    esi, OffsetPMMessage    ; 源数据偏移
186    mov    edi, (80 * 10 + 0) * 2    ; 目的数据偏移。屏幕第 10 行, 第 0 列。
187    cld
188.1:
189    lodsb
190    test    al, al
191    jz    .2
192    mov    [gs:edi], ax
193    add    edi, 2
194    jmp    .1
195.2:    ; 显示完毕
196
197    call    DispReturn
198
199    call    TestRead
200    call    TestWrite
201    call    TestRead
202
203    ; 到此停止
204  ;**********注意在此由32位代码段跳至16位代码段**********************
205    jmp    SelectorCode16:0
206
207; ------------------------------------------------------------------------
208TestRead:
209    xor    esi, esi
210    mov    ecx, 8
211.loop
212    mov    al, [es:esi]
213    call    DispAL
214    inc    esi
215    loop    .loop
216
217    call    DispReturn
218
219    ret
220; TestRead 结束-----------------------------------------------------------
221
222
223; ------------------------------------------------------------------------
224TestWrite:
225    push    esi
226    push    edi
227    xor    esi, esi
228    xor    edi, edi
229    mov    esi, OffsetStrTest    ; 源数据偏移
230    cld
231.1:
232    lodsb
233    test    al, al
234    jz    .2
235    mov    [es:edi], al
236    inc    edi
237    jmp    .1
238.2:
239
240    pop    edi
241    pop    esi
242
243    ret
244; TestWrite 结束----------------------------------------------------------
245
246
247; ------------------------------------------------------------------------
248; 显示 AL 中的数字
249; 默认地:
250;    数字已经存在 AL 中
251;    edi 始终指向要显示的下一个字符的位置
252; 被改变的寄存器:
253;    ax, edi
254; ------------------------------------------------------------------------
255DispAL:
256    push    ecx
257    push    edx
258
259    mov    ah, 0Ch            ; 0000: 黑底    1100: 红字
260    mov    dl, al
261    shr    al, 4
262    mov    ecx, 2
263.begin:
264    and    al, 01111b
265    cmp    al, 9
266    ja    .1
267    add    al, '0'
268    jmp    .2
269.1:
270    sub    al, 0Ah
271    add    al, 'A'
272.2:
273    mov    [gs:edi], ax
274    add    edi, 2
275
276    mov    al, dl
277    loop    .begin
278    add    edi, 2
279
280    pop    edx
281    pop    ecx
282
283    ret
284; DispAL 结束-------------------------------------------------------------
285
286
287; ------------------------------------------------------------------------
288DispReturn:
289    push    eax
290    push    ebx
291    mov    eax, edi
292    mov    bl, 160
293    div    bl
294    and    eax, 0FFh
295    inc    eax
296    mov    bl, 160
297    mul    bl
298    mov    edi, eax
299    pop    ebx
300    pop    eax
301
302    ret
303; DispReturn 结束---------------------------------------------------------
304
305SegCode32Len    equ    $ - LABEL_SEG_CODE32
306; END of [SECTION .s32]
307
308
309; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
310[SECTION .s16code]
311ALIGN    32
312[BITS    16]
313LABEL_SEG_CODE16:
314    ; 跳回实模式:
315  ;****************注意在此用normal选择子对段寄存器进行填充******************************
316    mov    ax, SelectorNormal
317    mov    ds, ax
318    mov    es, ax
319    mov    fs, ax
320    mov    gs, ax
321    mov    ss, ax
322
323    mov    eax, cr0
324    and    al, 11111110b
325    mov    cr0, eax
326
327;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;在此由保护模式切进实模式;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
328LABEL_GO_BACK_TO_REAL:
329    jmp    0:LABEL_REAL_ENTRY    ; 段地址会在程序开始处被设置成正确的值
330
331Code16Len    equ    $ - LABEL_SEG_CODE16
332
333; END of [SECTION .s16code]
334

注意一.在由保护模式切换到实模式之前,用normal选择子对段寄存器进行填充。

原因:

在切换到实模式之前,把一个指向似乎没有用的数据段的描述符Normal的选择子装载到DS和ES。这是为什么呢?

实模
式下
段描
述符
高速
缓冲
寄存
器的
内容

段寄存器

段基地址

段界限(固定)

段属性(固定)

存在性

特权级

已存取

粒度

扩展方向

可读性

可写性

可执行

堆栈大小

一致特权

CS

当前CS*16

0000FFFFH

Y

0

Y

B

U

Y

Y

Y

-

N

SS

当前SS*16

0000FFFFH

Y

0

Y

B

U

Y

Y

N

W

-

DS

当前DS*16

0000FFFFH

Y

0

Y

B

U

Y

Y

N

-

-

ES

当前ES*16

0000FFFFH

Y

0

Y

B

U

Y

Y

N

-

-

FS

当前FS*16

0000FFFFH

Y

0

Y

B

U

Y

Y

N

-

-

GS

当前GS*16

0000FFFFH

Y

0

Y

B

U

Y

Y

N

-

-

在分段管理机制中,每个段寄存器都配有段描述符高速缓冲寄存器,这些高速缓冲寄存器在实方式下仍发挥作用,只是内容上与保护模式下有所不同。如上表所示,其中“Y”表示“是”; “N”表示“否”;“B”表示字节;“U”表示向上扩展,“W”表示以字方式操作堆栈。段基地址仍是 32位,其值是相应段寄存器值(段值)乘以16,在把段值装载到段寄存器时刷新。由于其值是16位段值乘上16,所以在实模式下基地址实际上有效位只有20位。每个段的32位段界限都固定为0FFFFH,段属性的许多位也是固定的。所谓固定是指在实方式下不可设置这些属性值,只能继续沿用保护方式下所设置的值。因此,在准备结束保护模式回到实模式之前,要通过加载一个合适的描述符选择子(如实例代码中的Normal选择子)到有关段寄存器,以使得对应段描述符高速缓冲寄存器中含有合适的段界限和属性。

也就是说,在实模式下装载段寄存器并不会影响段告诉缓冲寄存器的值,比如段界限(其实在实模式也没有必要改变,应为段界限一直都是0ffffh),这也就是为甚麽所有讲保护模式的树在讲到有保护模式切换到实模式时都要加载一个normal选择子的原因了。

应为必须在保护模式下设置好段高速缓冲寄存器的值,因为一旦到了实模式下就不能在改变了。

经我试验,对于normal的描述符,其最重要是段界限一定要设置为0ffffh,如果不是这样,那莫在由保护模式跳转到实模式后会发生错误(对于上述代码如果把normal描述符的段界限改为别的的话,在跳转后会产生死循环的现象,具体是什么原因现在还不明确,哪位高人知道一定要告诉我啊~~)。其次就是属性的设置一定要设置为可读可写的,否则也会发生错误.

注意二:不能从32位代码段返回实模式,而只能从16位代码段返回。

原因:(书中说的)因为无法实现从32位代码段返回时CS高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)

对于这个解释还是不太明确,如果哪位高人明白其中的来龙去脉的话,请一定在下面留个言,给我解释一下,不胜感激.

保护模式与实模式的切换相关推荐

  1. CPU的三种工作模式:实模式、保护模式、长模式

    文章目录 **实模式** **保护模式** **长模式** **总结** 实模式 访问内存 实模式也就是说寄存器中存放的地址都是真实地址,比如下面这段程序: data SEGMENT ;定义一个数据段 ...

  2. 汇编:实模式->保护模式->实模式 的切换步骤

    1.设置必要的实模式环境,如实模式下的堆栈等. 2.初始化全局描述符表(GDT).局部描述符表(LDT)及中断描述符表(IDT)等. 3.保存实模式下的堆栈地址到某内存处,以便切换回实模式后恢复,如有 ...

  3. [书]x86汇编语言:从实模式到保护模式 -- 第17章 中断、任务切换、分页机制、平坦模型

    # 任务切换 内核任务.用户任务1.用户任务2,之前的轮询切换 利用RTC芯片的硬件中断来实现任务切换 计算机主板上有实时时钟芯片RTC,可以设置RTC芯片,使得它每次更新CMOS中的时间信息后,发出 ...

  4. 实模式和保护模式区别及寻址方式

    64KB-4GB-64TB? 我记得大学的汇编课程.组成原理课里老师讲过实模式和保护模式的区别,在很多书本上也有谈及,无奈本人理解和感悟能力实在太差,在很长一段时间里都没真正的明白它们的内含,更别说为 ...

  5. X86汇编语言从实模式到保护模式16:特权级和特权级保护

    目录 1. 特权级保护机制 1.1 基础段保护机制的不足 1.2 特权级划分 1.3 特权级的表示 1.3.1 当前特权级CPL 1.3.2 描述符特权级DPL 1.3.3 请求特权级RPL 1.4 ...

  6. 实模式、保护模式和虚拟8086模式

    参考自:实模式与保护模式解惑之(一)--二者的起源与区别(河西无名式) 概述:实模式和保护模式是处理器发展的两个非常重要的阶段.这两个模式下的编程也有着显著的不同,弄明实模式与保护模式的区别是理解操作 ...

  7. 06.实模式进入保护模式

    简介 上一节我们实现了从内核加载器中加载其它扇区代码并执行,但始终工作在实模式状态下.内存寻址方式和8086相同,由16位段寄存器的内容乘以16(10H)当做段基地址,加上16位偏移地址形成20位的物 ...

  8. (操作系统开发)从实模式---->保护模式---->IA-32e模式( 64位模式)

    实模式和保护模式都是CPU的工作模式. 实模式与保护模式介绍 在实模式下,程序可以操作任何地址空间,而且无法限制程序的执行权限.尽管这种模式给设置硬件功能带来许多方便,但却给程序执行的安全性和稳定性带 ...

  9. 深入理解计算机系统-之-内存寻址(二)--存储保护机制(CPU实模式与保护模式)

    cpu的保护模式由来 分段机制 8086的诞生,标志着Intel 正式进入了x86时代,这是个多么具有纪念意义的日子:1978-6-8.同时,8086的诞生也是处理器内存寻址技术的第一次飞跃. 对于一 ...

最新文章

  1. Facebook开源算法代码库,轻松复现前沿视频理解模型
  2. Smartform中如何设置背景阴影色(Shading)
  3. 生成configDataContextRefres失败:Error creating bean with name ‘configDataContextRefresher‘
  4. GNU make manual 翻译( 一百六十四)
  5. 【转】oracle回闪操作
  6. 今天算做正式开始SP开发吧,第一步当然是将down下来的资料好好地看一看,顺便也记下这些有用的地址...
  7. 对非线程安全类ListT的一些总结
  8. vue3 使用echarts
  9. 【QT】QT从零入门教程(八):图像灰度化
  10. asp.net panel 加html,ASP.NET中 Panel 控件的使用方法
  11. 8647服务器装系统,今天重新安装了系统,麻烦请红夜鬼先生进来帮我看一下
  12. Flutter:表单Form
  13. C语言 AES加解密
  14. 多变量微积分笔记(1)——向量和矩阵
  15. 理想汽车确认首席技术官王凯离职
  16. Didn't find class android.support.v7.widget.RecyclerView 解决办法 ———————————————— 版权声明:本文为CSDN博主「eag
  17. Selenium批量查询运动员技术等级
  18. matlab数据整周期截断,凯塞窗四谱线插值FFT的电力谐波分析方法
  19. 如何通过讯飞语音将文本合成后的语音保存到本地
  20. 臀部大的美女最令男人着迷

热门文章

  1. 右下角弹出程序的罪魁祸首原来是谷歌浏览器的通知
  2. Illustrator 教程:如何在 Illustrator 中添加图像?
  3. js打印去除页眉页脚url地址
  4. Windows server2003时间同步
  5. APP渗透—绕过反代理、反证书检测
  6. 《人生终要有一场触及灵魂的旅行》 毕淑敏 (又一碗没有心灵鸡胸的心灵鸡汤)
  7. 材质常用节点以及用法
  8. 导航软件哪个最好用?这里有3款最流行的导航软件
  9. 20220725树状数组入门反思
  10. 文/特约作者 孙思娜 图/CFP