实模式、保护模式的区别 实模式保护模式切换方法

实模式保护模式区别

      从80386开始,cpu有三种工作方式:实模式,保护模式和虚拟8086模式。只有在刚刚启动的时候是real-mode,等到linux操作系统运行起来以后就运行在保护模式。
 

       实模式只能访问地址在1M以下的内存称为常规内存,我们把地址在1M 以上的内存称为扩展内存。
 

       在保护模式下,全部32条地址线有效,可寻址高达4G字节的物理地址空间;
扩充的存储器分段管理机制和可选的存储器分页管理机制,不仅为存储器共享和保护提供了硬件支持,而且为实现虚拟存储器提供了硬件支持;
 

      支持多任务,能够快速地进行任务切换和保护任务环境;
 

      4个特权级和完善的特权检查机制,既能实现资源共享又能保证代码和数据的安全和保密及任务的隔离;
 

       支持虚拟8086方式,便于执行8086程序。

 

1.虚拟8086模式是运行在保护模式中的实模式,为了在32位保护模式下执行纯16位程序。它不是一个真正的CPU模式,还属于保护模式。

 

2.保护模式同实模式的根本区别是进程内存受保护与否 。可寻址空间的区别只是这一原因的果。
       实模式将整个物理内存看成分段的区域,程序代码和数据位于不同区域,系统程序和用户程序没有区别对待,而且每一个指针都是指向"实在"的物理地址。这样一来,用户程序的一个指针如果指向了系统程序区域或其他用户程序区域,并改变了值,那么对于这个被修改的系统程序或用户程序,其后果就很可能是灾难性的。为了克服这种低劣的内存管理方式,处理器厂商开发出保护模式。这样,物理内存地址不能直接被程序访问,程序内部的地址(虚拟地址)要由操作系统转化为物理地址去访问,程序对此一无所知。 至此,进程(这时我们可以称程序为进程了)有了严格的边界,任何其他进程根本没有办法访问不属于自己的物理内存区域,甚至在自己的虚拟地址范围内也不是可以任意访问的,因为有一些虚拟区域已经被放进一些公共系统运行库。这些区域也不能随便修改,若修改就会有: SIGSEGV(linux 段错误);非法内存访问对话框(windows 对话框)。

CPU启动环境为16位实模式,之后可以切换到保护模式。但从保护模式无法切换回实模式

 

3.事实上,现在的64位奔腾4处理器,拥有三种基本模式和一种扩展模式,
a)基本模式:
****保护模式:纯32位保护执行环境。
****实模式:纯16位无保护执行环境。
****系统管理模式:当SMI引脚为有效进入系统管理模式,首先保存当前的CPU上下文。它有独立的地址空间,用来执行电源管理或系统安全方面的指令。
b)扩展模式:****IA-32e模式,64位操作系统运行在该模式。该模式有两种子模式:
 

1)**兼容模式:该模式下,64位操作系统运行在32位兼容环境,能正常运行16,32位应用程序就像基本的保护模式一样,访问32位地址空间,但不能运行纯16位实模式程序(就是不能运行虚拟86模式程序了)。
 

2)**64位模式:在该模式下,处理器完全执行64位指令,使用64位地址空间和64操作数,运行16,32位程序必须切换到兼容模式。
IA-32e子模式的切换完全基于代码段寄存器。这样一来,运行在IA-32e模式中(64位)的OS完全可以无缝的运行所有16,32,64为应用程序,通过设置32位后的CS。

 

实模式保护模式切换方法

        实例一的逻辑功能是,以十六进制数的形式显示从内存地址110000H开始的256个字节的值。本实例指定该内存区域的目的仅仅是想说明切

换到保护模式的必要性,因为在实模式下不能该指定内存区域,只有在保护模式下才能到该指定区域

 

本实例的具体实现步骤是:作切换到保护方式的准备;切换到保护方式;把指定内存区域的内容传送到位于常规内存的缓冲区中;切换回实模式;显示缓冲区内容。

1.包含文件

       386保护模式汇编语言程序用到的包含文件如下所示,该包含文件在后面的程序中还要用到。

名称:386SCD.INC

功能:符号常量等的定义

IFNDEF __386SCD_INC

__386SCD_INC EQU 1

386P

打开A20地址线EnableA20 MACRO

push ax

in al,92h

or al,00000010b

out 92h,al

pop ax

ENDM

关闭A20地址线

DisableA20 MACRO

push ax

in al,92h

and al,11111101b

out 92h,al

pop ax

ENDM

16位偏移的段间直接转移指令的宏定义

JUMP16 MACRO Selector,Offset

DB 0eah ;操作码

DW Offset ;16位偏移量

DW Selector ;段值或段选择子

ENDM

 

32位偏移的段间直接转移指令的宏定义

COMMENT JUMP32

JUMP32 MACRO Selector,Offset

DB 0eah ;操作码

DD OFFSET

DW Selector ;段值或段选择子

ENDM

JUMP32

JUMP32 MACRO Selector,Offset

DB 0eah ;操作码

DW OFFSET

DW 0

DW Selector ;段值或段选择子

ENDM

16位偏移的段间调用指令的宏定义

CALL16 MACRO Selector,Offset

DB 9ah ;操作码

DW Offset ;16位偏移量

DW Selector ;段值或段选择子

ENDM

32位偏移的段间调用指令的宏定义

COMMENT CALL32

CALL32 MACRO Selector,Offset

DB 9ah ;操作码

DD Offset

DW Selector ;段值或段选择子

ENDM

CALL32

CALL32 MACRO Selector,Offset

DB 9ah ;操作码

DW Offset

DW 0

DW Selector ;段值或段选择子

ENDM

存储段描述符结构类型定义

Desc STRUC

LimitL DW 0 ;段界限

BaseL DW 0 ;段基地址

BaseM DB 0 ;段基地址

Attributes DB 0 ;段属性

LimitH DB 0 ;段界限

BaseH DB 0 ;段基地址

Desc ENDS

门描述符结构类型定义

Gate STRUC

OffsetL DW 0 ;32位偏移的低16位

Selector DW 0 ;选择子

DCount DB 0 ;双字计数

GType DB 0 ;类型

OffsetH DW 0 ;32位偏移的高16位

Gate ENDS

伪描述符结构类型定义

PDesc STRUC

Limit DW 0 ;16位界限

Base DD 0 ;32位基地址

PDesc ENDS

任务状态段结构类型定义

TSS STRUC

TRLink DW 0 ;链接字段

DW 0 ;不使用,置为0

TRESP0 DD 0 ;0级堆栈指针

TRSS0 DW 0 ;0级堆栈段寄存器

DW 0 ;不使用,置为0

TRESP1 DD 0 ;1级堆栈指针

TRSS1 DW 0 ;1级堆栈段寄存器

DW 0 ;不使用,置为0

TRESP2 DD 0 ;2级堆栈指针

TRSS2 DW 0 ;2级堆栈段寄存器

DW 0 ;不使用,置为0

TRCR3 DD 0 ;CR3

TREIP DD 0 ;EIP

TREFlag DD 0 ;EFLAGS

TREAX DD 0 ;EAX

TRECX DD 0 ;ECX

TREDX DD 0 ;EDX

TREBX DD 0 ;EBX

TRESP DD 0 ;ESP

TREBP DD 0 ;EBP

TRESI DD 0 ;ESI

TREDI DD 0 ;EDI

TRES DW 0 ;ES

DW 0 ;不使用,置为0

TRCS DW 0 ;CS

DW 0 ;不使用,置为0

TRSS DW 0 ;SS

DW 0 ;不使用,置为0

TRDS DW 0 ;DS

DW 0 ;不使用,置为0

TRFS DW 0 ;FS

DW 0 ;不使用,置为0

TRGS DW 0 ;GS

DW 0 ;不使用,置为0

TRLDTR DW 0 ;LDTR

DW 0 ;不使用,置为0

TRTrip DW 0 ;调试陷阱标志

TRIOMap DW $+2 ;指向I/O许可位图区的段内偏移

TSS ENDS

存储段描述符类型值说明

ATDR EQU 90h ;存在的只读段类型值

ATDW EQU 92h ;存在的可读写段属性值

ATDWA EQU 93h ;存在的已可读写段类型值

ATCE EQU 98h ;存在的只执行代码段属性值

ATCER EQU 9ah ;存在的可执行可读代码段属性值

ATCCO EQU 9ch ;存在的只执行一致代码段属性值

ATCCOR EQU 9eh ;存在的可执行可读一致代码段属性值

系统段描述符类型值说明

ATLDT EQU 82h ;局部描述符表段类型值

ATTaskGate EQU 85h ;任务门类型值

AT386TSS EQU 89h ;可用386任务状态段类型值

AT386CGate EQU 8ch ;386调用门类型值

AT386IGate EQU 8eh ;386中断门类型值

AT386TGate EQU 8fh ;386陷阱门类型值

DPL值说明

DPL0 EQU 00h ;DPL=0

DPL1 EQU 20h ;DPL=1

DPL2 EQU 40h ;DPL=2

DPL3 EQU 60h ;DPL=3

RPL值说明

RPL0 EQU 00h ;RPL=0

RPL1 EQU 01h ;RPL=1

RPL2 EQU 02h ;RPL=2

RPL3 EQU 03h ;RPL=3

IOPL值说明

IOPL0 EQU 0000h ;IOPL=0

IOPL1 EQU 1000h ;IOPL=1

IOPL2 EQU 2000h ;IOPL=2

IOPL3 EQU 3000h ;IOPL=3

其它常量值说明

D32 EQU 40h ;32位代码段标志

GL EQU 80h ;段界限以4K为单位标志

TIL EQU 04h ;TI=1

VMFL EQU 00020000h ;VMF=1

VMFLW EQU 0002h

IFL EQU 00000200h ;IF=1

RFL EQU 00010000h ;RF=1

RFLW EQU 0001h

NTL EQU 00004000h ;NT=1

分页机制使用的常量说明

PL EQU 1 ;页存在属性位

RWR EQU 0 ;R/W属性位值,读/执行

RWW EQU 2 ;R/W属性位值,读/写/执行

USS EQU 0 ;U/S属性位值,系统级

USU EQU 4 ;U/S属性位值,用户级

ENDIF

2.实例源程序

实例一的源程序如下所示:

名称:ASM1.ASM

;功能:演示实方式和保护方式切换

INCLUDE 386SCD.INC

字符显示宏指令的定义

EchoCh MACRO ascii

mov ah,2

mov dl,ascii

int 21h

ENDM

DSEG SEGMENT USE16 ;16位段

GDT LABEL BYTE ;全局描述符表

DUMMY Desc ;空描述符

Code Desc 0ffffh,,,ATCE,, ;代码段描述符

DataS Desc 0ffffh,0,11h,ATDW,, ;源段描述符

DataD Desc 0ffffh,,,ATDW,, ;目标段描述符

GDTLen = $-GDT ;全局描述符表长度

VGDTR PDesc GDTLen-1, ;伪描述符

Code_Sel = Code-GDT ;代码段选择子

DataS_Sel = Datas-GDT ;源段选择子

DataD_Sel = DataD-GDT ;目标段选择子

BufLen = 256 ;缓冲区字节长度

Buffer DB BufLen DUP ;缓冲区

DSEG ENDS ;段定义结束

CSEG SEGMENT USE16 ;16位代码段

ASSUME CS:CSEG,DS:DSEG

Start PROC

mov ax,DSEG

mov ds,ax

;准备要加载到GDTR的伪描述符

mov bx,16

mul bx

add ax,OFFSET GDT ;计算并设置基地址

adc dx,0 ;界限已在定义时设置好

mov WORD PTR VGDTR.Base,ax

mov WORD PTR VGDTR.Base+2,dx

设置代码段描述符

mov ax,cs

mul bx

mov WORD PTR Code.BaseL,ax ;代码段开始偏移为0

mov BYTE PTR Code.BaseM,dl ;代码段界限已在定义时设置好

mov BYTE PTR Code.BaseH,dh

设置目标段描述符

mov ax,ds

mul bx ;计算并设置目标段基址

add ax,OFFSET Buffer

adc dx,0

mov WORD PTR DataD.BaseL,ax

mov BYTE PTR DataD.BaseM,dl

mov BYTE PTR DataD.BaseH,dh

加载GDTR

lgdt QWORD PTR VGDTR

cli ;关中断

EnableA20 ;打开地址线A20

切换到保护方式

mov eax,cr0

or eax,1

mov cr0,eax

清指令预取队列,并真正进入保护方式

JUMP16 Code_Sel,OFFSET Virtual

Virtual: ;现在开始在保护方式下运行

mov ax,DataS_Sel

mov ds,ax ;加载源段描述符

mov ax,DataD_Sel

mov es,ax ;加载目标段描述符

cld

xor si,si

xor di,di ;设置指针初值

mov cx,BufLen/4 ;设置4字节为单位的缓冲区长度

repz movsd ;传送

切换回实模式

mov eax,cr0

and al,11111110b

mov cr0,eax

清指令预取队列,进入实方式

JUMP16 SEG Real,OFFSET Real

Real: ;现在又回到实方式

DisableA20

sti

mov ax,DSEG

mov ds,ax

mov si,OFFSET Buffer

cld

mov bp,BufLen/16

NextLine: mov cx,16

NextCh: lodsb

push ax

shr al,1

call ToASCII

EchoCh al

pop ax

call ToASCII

EchoCh al

EchoCh ‘ ‘

loop NextCh

EchoCh 0dh

EchoCh 0ah

dec bp

jnz NextLine

mov ax,4c00h

int 21h

Start ENDP

ToASCII PROC

and al,0fh

add al,90h

daa

adc al,40h

daa

ret

ToASCII ENDP

CSEG ENDS ;代码段定义结束

END Start

3.关于实例步骤的注释

       在源程序的开头首先包含了文件“386SCD.INC”,在此包含文件中定义了保护模式程序设计要用到的一些结构、宏及常量。下面对各实现步骤作些说明。

 

切换到保护方式的准备工作

       在从实模式切换到保护模式之前,必须作必要的准备。准备工作的内容根据实际而定。最起码的准备工作是建立合适的全局描述符表,并使用GDTR指向该 GDT。因为在切换到保护方式时,至少要把代码段的选择子装载到CS,所以GDT中至少含有代码段的描述符。

       从本实例源程序可见,全局描述符表GDT仅有四个描述符:第一个是空描述符;第二个是代码段描述符;第三个和第四个分别为源数据段及目标段描述符。本实例各描述符中的段界限是在定义时设置的,并且除伪描述符VGDTR中的界限按GDT的实际长度设置外,各使用的存储段描述符的界限都规定为0FFFFH。另外,描述符中的段属性也根据所描述段的类型被预置,各属性的定义在包含文件386SCD.INC中均有说明。从属性值可知,这三个段都是16位段。

       由于在切换到保护方式后就要引用GDT,所以在切换到保护方式前必须装载GDTR。实例中使用如下指令装载GDTR:

LGDT QWORD PTR VGDTR

       该指令的功能是把存储器中的伪描述符VGDTR装入到全局描述符表寄存器GDTR中。伪描述符VGDTR的结构如前所述结构类型PDESC所示,低字是以字节位单位的全局描述符表段的界限,高双字为描述符表段的线性基地址。本实例中未涉及到局部描述符表及中断描述符表,后面的文章将作详细说明。

 

由实模式切换到保护模式

       在做好准备后,从实模式切换到保护模式并不难。原则上只要把控制寄存器CR0中的PE位置1即可。本实例采用如下三条指令设置PE位:

mov eax,cr0

or eax,1

mov cr0,eax

       实际情况要比这复杂些。执行上面的三条指令后,处理器转入保护模式,但CS中的内容还是实模式下代码段的段值,而不是保护模式下代码段的选择子,所以在取指令之前得把代码段的选择子装入CS。为此,紧接着这三条指令,安排一条如下所示的段间转移指令:

JUMP16 Code_Sel , OFFSET Virtual

       这条段间转移指令 在实模式下被预取并在保护方式下被执行 。利用这条段间转移指令可把保护模式下代码段的选择子装入CS,同时也刷新指令预取队列。从此真正进入保护模式。

 

由保护模式切换到实模式

       在80386上,从保护模式切换到实模式的过程类似于从实模式切换到保护模式。原则上只要把控制寄存器CR0中的PE位清0即可。实际上,在此之后也要安排一条段间转移指令,一方面清指令预取队列,另一方面把实模式下代码段的段值送CS。 这条段间转移指令在保护方式下被预取并在实模式下被执行 。

 

保护模式下的传送

      首先,把源数据段和目标段的选择子装入DS和ES寄存器,这两个描述符已在实模式下设置好,把选择子装入段寄存器就意味着把包括基地址在内的段信息装入到了段描述符高速缓冲寄存器。然后设置指针寄存器SI和DI的初值,也设置计数器CX的初值。根据预置的段属性,在保护方式下,代码段也仅是16位段,串操作指令只使用16位的SI、DI和CX等寄存器。最后利用串操作指令实施传送。

 

显示缓冲区中的内容

       由于缓冲区在常规内存中,所以在实模式下根据要求按十六进制显示其内容是很容易理解的,这里就不再多说。

 

4.内存映象

       在源程序中没有把GDT作为一个单独的段对待,但在进入保护方式后,它是一个独立的段。从对代码段和源数据段描述符所赋的基地址和段界限值可见,代码段和数据段有部分覆盖。尽管这样做不利于代码和的安全,但如果需要,这样做是可行的。本实例运行时的内存映象如下图所示。

 

5.特别说明

       作为第一个实模式和保护模式切换的例子,本实例作了大量的简化处理。

      通常,由实模式切换到保护模式的准备工作还应包含建立中断描述符表。但本实例没有建立中断描述符表。为此,要求整个过程在关中断的情况下进行;要求不使用软中断指令;假设不发生任何异常。否则会导致系统崩溃。

       本实例未使用局部描述符表,所以在进入保护模式后没有设置局部描述符表寄存器LDTR。为此,在保护模式下使用的段选择子都指定GDT中的描述符。

       本实例未定义保护模式下的堆栈段,GDT中没有堆栈段描述符,在保护模式下没有设置SS,所以在保护方式下没有涉及堆栈操作的指令。

      本实例各描述符特权级DPL和各选择子的请求特权级RPL均为0,在保护方式下运行时的当前特权级CPL也是0。

       本实例没有采用分页管理机制,也即CR0中的PG位为0,线性地址就是存储单元的物理地址。

 

6.打开和关闭地址线A20

      PC及其兼容机的第21根地址线较特殊,计算机系统中一般安排一个 “门”控制该地址线是否有效。为了地址在1M以上的存储单元,应先打开控制地址线A20的“门”。这种设置与实模式下只使用最低端的1M字节存储空间有关,与处理器是否工作在实模式或保护方式无关,即使在关闭地址线A20时,也可进入保护模式。

       如何打开和关闭地址线A20与计算机系统的具体设置有关。在本文中介绍的包含文件386SCD.INC中定义了两个宏,打开地址线A20的宏 EnableA20和关闭地址线A20的宏DisableA20,此两个宏指令在一般的PC兼容机上都是可行的。

二演示32位代码段和16位代码段切换的实例

       实例二的逻辑功能是,以十六进制数和ASCII字符两种形式显示从内存地址100000H开始的16个字节的内容。

       从功能上看,本实例类似于实例一,但在实现方法上却有了改变,它更能反映出实模式和保护模式切换的情况。具体实现步骤是:作切换到保护方式的准备;切换到保护方式的一个32位代码段;把指定内存区域的内容以字节为单位,转换成对应的十六进制数的ASCII码,并直接填入显示缓冲区实现显示;再变换到保护方式下的一个16位代码段;把指定内存区域的内容直接作为ASCII码填入显示缓冲区中实现显示;切换回实模式。

1.实例二源程序

实例二的源程序如下所示:

名称:ASM2.ASM

功能:演示实方式和保护方式切换

INCLUDE 386SCD.INC

DSEG SEGMENT USE16 ;16位段

GDT LABEL BYTE ;全局描述符表

DUMMY Desc ;空描述符

Normal Desc 0ffffh,,,ATDW,, ;规范段描述符

Code32 Desc C32Len-1,,,ATCE,D32, ;32位代码段描述符

Code16 Desc 0ffffh,,,ATCE,, ;16位代码段描述符

DataS Desc DataLen-1,0,10h,ATDR,, ;源段描述符

DataD Desc 3999,8000h,0bh,ATDW,, ;显示缓冲区描述符

Stacks Desc StackLen-1,,,ATDW,, ;堆栈段描述符

GDTLen = $-GDT ;全局描述符表长度

VGDTR PDesc GDTLen-1, ;伪描述符

SaveSP DW ? ;用于保存SP寄存器

SaveSS DW ? ;用于保存SS寄存器

Normal_Sel = Normal-GDT ;规范段描述符选择子

Code32_Sel = Code32-GDT ;32位代码段选择子

Code16_Sel = Code16-GDT ;16位代码段选择子

DataS_Sel = Datas-GDT ;源段选择子

DataD_Sel = DataD-GDT ;目标段选择子

Stacks_Sel = Stacks-GDT ;堆栈段描述符选择子

DtaLen = 16

DSEG ENDS ;段定义结束

StackSeg SEGMENT PARA STACK USE16

StackLen = 256

DB StackLen DUP

StackSeg ENDS

CSEG1 SEGMENT USE16 ‘REAL‘ ;16位代码段

ASSUME CS:CSEG1,DS:DSEG

Start PROC

mov ax,DSEG

mov ds,ax

准备要加载到GDTR的伪描述符

mov bx,16

mul bx

add ax,OFFSET GDT ;计算并设置基地址

adc dx,0 ;界限已在定义时设置好

mov WORD PTR VGDTR.Base,ax

mov WORD PTR VGDTR.Base+2,dx

设置32位代码段描述符

mov ax,CSEG2

mul bx

mov WORD PTR Code32.BaseL,ax

mov BYTE PTR Code32.BaseM,dl

mov BYTE PTR Code32.BaseH,dh

设置16位代码段描述符

mov ax,CSEG3

mul bx

mov WORD PTR Code16.BaseL,ax ;代码段开始偏移为0

mov BYTE PTR Code16.BaseM,dl ;代码段界限已在定义时设置好

mov BYTE PTR Code16.BaseH,dh

设置堆栈段描述符

mov ax,ss

mov WORD PTR SaveSS,ax

mov WORD PTR SaveSP,sp

mov ax,StackSeg

mul bx

mov WORD PTR Stacks.BaseL,ax

mov BYTE PTR Stacks.BaseM,dl

mov BYTE PTR Stacks.BaseH,dh

;加载GDTR

lgdt QWORD PTR VGDTR

cli ;关中断

EnableA20 ;打开地址线A20

切换到保护方式

mov eax,cr0

or al,1

mov cr0,eax

清指令预取队列,并真正进入保护方式

JUMP16 Code32_Sel,OFFSET SPM32

ToReal: ;现在又回到实方式

mov ax,DSEG

mov ds,ax

mov sp,SaveSP

mov ss,SaveSS

DisableA20

sti

mov ax,4c00h

int 21h

Start ENDP

CSEG1 ENDS ;代码段定义结束

CSEG2 SEGMENT USE32 ‘PM32‘

ASSUME CS:CSEG2

SPM32 PROC

mov ax,Stacks_Sel

mov ss,ax

mov esp,StackLen

mov ax,DataS_Sel

mov ds,ax

mov ax,DataD_Sel

mov es,ax

xor esi,esi

xor edi,edi

mov ecx,DataLen

cld

Next: lodsb

push ax

CALL ToASCII

mov ah,7

shl eax,16

pop ax

shr al,4

CALL ToASCII

mov ah,7

stosd

mov al,20h

stosw

loop Next

JUMP32 Code16_Sel,OFFSET SPM16

SPM32 ENDP

ToASCII PROC

and al,00001111b

add al,30h

cmp al,39h

jbe Isdig

add al,7

IsDig: ret

ToASCII ENDP

C32Len = $

CSEG2 ENDS

CSEG3 SEGMENT USE16 ‘PM16‘

ASSUME CS:CSEG3

SPM16 PROC

xor si,si

mov di,DataLen*3*2

mov ah,7

mov cx,DataLen

AGain: lodsb

stosw

loop AGain

mov ax,Normal_sel

mov ds,ax

mov es,ax

mov ss,ax

mov eax,cr0

and al,11111110b

mov cr0,eax

jmp FAR PTR ToReal

SPM16 ENDP

CSEG3 ENDS

END Start

2.关于实现步骤的注释
切换到保护模式的准备工作

       建立全局描述符表,这里的全局描述符表含有两个16位段的描述符、一个16位代码段的描述符和一个16位的堆栈段描述符。此外,GDT中还有一个32位的代码段描述符,描述32位代码段,该描述符的属性字段中的D位为1。

由实模式切换到保护模式

       由实模式切换到保护模式32位代码段的方法与切换到16位代码段的方法相同。由保护模式16位代码段切换回实模式的方法与实例一相似。

       在保护模式下,通过如下直接段间转移指令从32位代码段切换到16位代码段:

JUMP32 Code16_Sel , OFFSET SPM16

      从该宏指令的定义可知,该转移指令含48位指针,其高16位是16位代码段的选择子,低32位是16位代码段的入口偏移。 该指令在32位方式下预取并执行 。由于在32位方式下执行,所以要使用48位指针。

显示指定内存区域的内容

      在本实例中,采用直接写显示缓冲区的方法实现显示。假设显示缓冲区的开始物理地址是0B8000H, 3号文本显示模式,在屏幕的第一行进行显示。

3.特别说明

      本实例在保护方式下使用了涉及堆栈操作的指令,因此建立了一个16位的保护模式下的堆栈段。

本实例仍作了大量的简化处理。如:没有建立IDT和LDT等,各特权级均是0。也没有采用分页管理机制。

你可能感兴趣的:(操作系统)