Orange’s学习笔记(二)

保护模式
1、为什么GDT(全局描述符表)中第一个描述符为空
答:全局描述符表实际上是为80386以上的32位cpu在保护模式下提供段式寻址机制的一个索引表,这个表的每一个表项(8个字节)描述了一段地址的起始地址、界限以及属性,原来的实模式下的段寄存器存储的值不在是地址的一部分,而其中的高13位表示的是GDT中表项的索引,低3位分别表示TI(1位)和RPL(2位)。GDT的第一个(索引为0)描述符很特殊,8个字节的值全为0,网上查阅资料基本上有三种说法,说法一:GDT的第一个描述符代表NULL的意思,是针对那些没有LDT的任务或用户进程的程序;说法二:代表GDT的起始地址;说法三:CPU规定(ps:处理器规定,GDT中的第一个描述符必须是空描述符。这是什么原因呢?因为很多时候,寄存器和内存单元的初始值都会为0,再加上程序设计有问题,就会在无意中用全0的索引来选择描述符,这当然是不好的。因此,处理器要求将第一个描述符定义成空描述符;而且在进行特权级变换的长返回时,CPU进行的最后一步工作是:检查ds、es、fs、gs的值,如果其中哪一个寄存器指向的段的DPL小于CPL(此规则不适用于一致代码段),那么一个空描述符会被加载到该寄存器)。
我注释掉了GDT中的第一个描述符就不可以运行了,代码如下:

%include "pm.inc"
org 07c00h
    jmp LABEL_BEGIN

[SECTION .gdt]
G_DESC_BEGIN:
;G_DESC:        Descriptor  0,  0,  0                   
G_DESC_CODE32:  Descriptor  0,  SegCode32Len-1, DA_C|DA_32      ;非一致32位代码段
G_DESC_VIDEO:   Descriptor  0B8000h,    0ffffh, DA_DRW          ;显存段

GdtLen  equ $-G_DESC_BEGIN
GdtPtr  dw  GdtLen-1
        dd  0

SelectorCode32  equ G_DESC_CODE32-G_DESC_BEGIN
SelectorVideo   equ G_DESC_VIDEO-G_DESC_BEGIN

[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
    mov ax,cs
    mov ds,ax

    ;初始化32位代码段描述符
    xor eax,eax
    mov ax,cs
    shl eax,4
    add eax,LABEL_SEG_CODE32
    mov word [G_DESC_CODE32+2],ax
    shr eax,16
    mov byte [G_DESC_CODE32+4],al
    mov byte [G_DESC_CODE32+7],ah

    ;为加载GDTR做准备
    xor eax,eax
    mov ax,ds
    shl eax,4
    add eax,G_DESC_BEGIN
    mov dword [GdtPtr+2],eax

    lgdt [GdtPtr]

    cli

    in al,92h
    or al,00000010
    out 92,al

    mov eax,cr0
    or eax,1
    mov cr0,eax

    jmp dword SelectorCode32:0

[SECTION .s32]
[BITS 32]
LABEL_SEG_CODE32:
    mov ax,SelectorVideo
    mov gs,ax
    mov ah,0Ch
    mov al,'G'
    mov [gs:((80*18+0)*2)],ax
    mov al,'D'
    mov [gs:((80*18+1)*2)],ax
    mov al,'T'
    mov [gs:((80*18+2)*2)],ax
    jmp $

SegCode32Len    equ $-LABEL_SEG_CODE32

2、G_DESC_NORMAL描述符的作用
从保护模式跳转回实模式,在准备结束保护模式回到实模式之前,需要加载一个合适的描述符选择子到有关的段寄存器,以使对应段描述符高速缓冲寄存器 (见后面的解释)中含有合适的段界限和属性(这里正确的段界限显然是64K,即0ffffh,属性应该是DA_DRW,即90h可读写数据段),而且,不能从32位代码段返回实模式,只能从16位代码段中返回。这是因为无法实现从32位代码段返回时cs高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)。(高速缓冲寄存器: 在实模式下,段寄存器含有段值,为访问存储器形成物理地址时,处理器引用相应的某个段寄存器并将其值乘以16,形成20位的段基地址。在保护模式下,段寄存器含有段选择子,如上所述,为了访问存储器形成线性地址时,处理器要使用选择子所指定的描述符中的基地址等信息。为了避免在每次存储器访问时,都要访问描述符表而获得对应的段描述符,从80286开始每个段寄存器都配有一个高速缓冲寄存器,称之为段描述符高速缓冲寄存器 或描述符投影寄存器,对程序员而言它是不可见的。每当把一个选择子装入到某个段寄存器时,处理器自动从描述符表中取出相应的描述符,把描述符中的信息保存到对应的高速缓冲寄存器中。此后对该段访问时,处理器都使用对应高速缓冲寄存器中的描述符信息,而不用再从描述符表中取描述符。)
新增的Normal描述符,段界限64K,属性DA_DRW,在返回实模式之前把对应选择子SelectorNormal加载到ds、es和ss正好合适。

3、A20地址线
8086有20位地址总线寻址空间为1M,在理论上段:偏移的寻址模式在实模式下最大地址为FFFF:FFFF=10FFEF,这显然超过了20位地址总线所能表示的最大地址值(FFFFF),而试图访问超过1M以上地址的空间并不会造成错误,而是会回卷,即10FFEF只会表示0FFEF(10FFEF%100000)的物理地址值。但是到了80286(24位地址总线)以上,真的可以访问到1M以上的地址空间了,这样的寻址方式会造成向上不兼容,所以IBM提出了一个方案,通过8042键盘控制器控制索引为20(从0开始)的地址位,在实模式下,关闭A20地址线,这时如果cpu有超过20位的地址线,则A20始终为0,所以FFFF:FFFF还是表示0FFEF的地址值,这样8086、80286、80386等等cpu在实模式下寻址方式就很好的兼容起来,绝大多数IBM PC兼容机默认的A20地址线是被关闭的。由于在当时没有更好的方法来解决这个问题,所以IBM使用了键盘控制器来操作A20地址线

你可能感兴趣的:(Orange-s学习)