实验9 保护模式编程基础
来源:互联网 发布:软件质量模型 编辑:程序博客网 时间:2024/05/21 06:46
实验9 保护模式编程基础
在保护模式下,可寻址高达4GB(甚至更多)的物理地址空间;支持存储器分段管理机制和分页管理机制;支持多任务;支持4个特权级和配套的特权检查机制,区分不同级别的代码。操作系统(如Windows、Linux等)正是依赖于这些特性来实现虚拟内存、内核/用户模式、多任务等功能。
9.1 虚拟机开发环境
实模式与保护模式的切换,以及保护模式下的中断、DMA处理等程序必须在特权级0下执行,而Windows应用程序在特权级3环境中运行,只有系统内核和设备驱动程序才能运行在特权级0。因此,这些实验需要在DOS环境下进行。
借助于虚拟机技术,可以在Windows环境下完成这些实验。图9-1就是在虚拟机中运行DOS操作系统和real2pro.exe的结果。
图9-1 在虚拟机中完成保护模式实验
1. 虚拟机
虚拟机软件可在一台计算机(称为宿主机)上模拟出若干台计算机,模拟出的计算机(称为客户机)都有自己单独的硬件配置,可以安装单独的操作系统。例如,宿主计算机运行Windows操作系统,在上面运行虚拟机软件,虚拟出的计算机可以运行Linux操作系统。这2个操作系统各自独立运行,互不干扰。
VirtualBox是德国InnoTek公司开发的虚拟机软件,可以运行在Windows和Linux上,客户机上可以安装Windows、DOS、Linux、OpenBSD等操作系统。除了VirtualBox软件以外,常用的虚拟机软件还有VMWare、Virtual PC等。
2. 建立虚拟软驱
在保护模式实验中,宿主机运行Windows,客户机运行DOS。DOS和Windows之间的共享采用虚拟软驱来完成。
VFD是一个虚拟软驱软件。运行vfdwin.exe(在C:/asm/tools/vfd21目录下),如图9-2所示,按以下步骤在计算机上虚拟出一个软驱(B:):
(1) 在“Driver”页中,按“Browse…”选择C:/asm/tools/vfd21/vfd.sys;
(2) 按“Install”按钮安装驱动程序;
(3) 按“Start” 按钮启动驱动程序;
(4) 在“Drive 0”页中,按“Change…”选择B:;
(5) 按“Open”按钮,再按“Browse…”选择C:/asm/tools/vfd21/ floppyA.img;Disk Type选择为FILE。
图9-2 建立虚拟软驱
这样,计算机上就增加了一个虚拟软驱B:了。
3. 创建DOS虚拟机
安装VirtualBox软件,启动VirtualBox后,点击工具栏上的“新建”按钮。按以下步骤在计算机上创建一个虚拟机:
(1) 如图9-3所示,虚拟机名称为“DOS”,在系统类型种选择“DOS”,按“下一步”;
(2) 提示系统内存容量,缺省为32MB,直接按“下一步”;
(3) 图9-4中,提示选择虚拟硬盘时,按“现有”按钮,出现图9-5所示对话框;
(4) 在虚拟硬盘管理器中,按“注册”按钮,指定虚拟硬盘映像文件为C:/asm/tools/vbox/ HDD0.VDI,如图9-6所示。在图9-5的虚拟硬盘管理器,按“选择”按钮;
(5) 一直按“下一步” 按钮,直到“完成”为止。
图9-3 设置虚拟机名称
图9-4 选择虚拟硬盘
图9-5 虚拟硬盘管理器
图9-6 指定虚拟硬盘映像
在图9-7的VirtualBox窗口左边选中DOS客户机,点击工具栏中的“设置”按钮,选择软驱,选中“加载软驱”,主机上的软驱设为“B:”。
图9-7 VirtualBox主窗口界面
图9-8 设置DOS虚拟机的软驱
在VirtualBox窗口(图9-7)中选择DOS客户机,点击工具栏中的“启动”按钮,启动进入DOS界面。此时,DOS客户机显示为“A>”,这里驱动器A中的文件系统和宿主机B:中完全一致。可以在Windows中编辑修改程序、编译连接,如图9-1所示。
图9-9 在Windows中编译、连接real2pro.asm
程序编译通过后,用鼠标左键点击DOS客户机窗口,在DOS客户机中执行real2pro.exe,结果如图9-1所示。
程序出现错误时,可执行菜单“虚拟电脑”→“重启”,重新启动DOS客户机。
需要切换到Windows环境时,按键盘右边的Ctrl键即可。
要关闭DOS客户机,选择菜单“虚拟电脑”→“关闭”,再在对话框中选择“强制关机”。
9.2 实模式与保护模式的切换
程序中定义了两个缓冲区:Buffer和Buffer2,从实模式切换到保护模式,将Buffer中的全部64个字节复制到Buffer2中,再回到实模式下,将Buffer2中的内容显示出来。
在程序的数据段DSEG中,定义了一个GDT,其中包括4个段描述符:空、代码段、数据段D、数据段E。VGDTR 占6个字节,用于存放GDTR的值。
Buffer和Buffer2分别位于数据段DSEG和ESEG中。
程序首先在实模式下执行,执行过程为:
(1) 设置3个段描述符(代码段、数据段D、数据段E)的基地址,这些段描述符的其他字段(限长、属性等)已经在定义时进行了赋值。
(2) 加载GDTR,使CPU在保护模式下能够访问GDT。
(3) 在实模式时,A20门处于关闭状态。调用EnableA20宏将A20门打开,A20门打开时,CPU产生的A20地址有效,A20门关闭时,A20地址线总是为0。
(4) 将CR0的第0位置1,跳转到保护模式的Virtual标号,进入保护模式下执行。
在保护模式下,执行过程为:
(1) 为DS、ES赋值。DS=0010H,SS=0018H,分别指向数据段DSEG和ESEG。
(2) 将数据段DSEG的Buffer复制到ESEG的Buffer2。
(3) 将CR0的第0位清0,跳转到实模式的Real标号,回到实模式下执行。
在实模式下,显示出Buffer2的内容。
;程序清单: real2pro.asm(实模式与保护方式之间的切换)
.386P
;存储段描述符结构类型定义
Desc STRUC
LimitL DW 0 ;段界限(BIT0-15)
BaseL DW 0 ;段基地址(BIT0-15)
BaseM DB 0 ;段基地址(BIT16-23)
Attributes DB 0 ;段属性
LimitH DB 0 ;段界限(BIT16-19)(含段属性的高4位)
BaseH DB 0 ;段基地址(BIT24-31)
Desc ENDS
;伪描述符结构类型定义(用于装入全局或中断描述符表寄存器)
PDesc STRUC
Limit DW 0 ;16位界限
Base DD 0 ;32位基地址
PDesc ENDS
;存储段描述符类型值说明
ATDR EQU 90h ;存在的只读数据段类型值
ATDW EQU 92h ;存在的可读写数据段属性值
ATDWA EQU 93h ;存在的已访问可读写数据段类型值
ATCE EQU 98h ;存在的只执行代码段属性值
ATCER EQU 9ah ;存在的可执行可读代码段属性值
ATCCO EQU 9ch ;存在的只执行一致代码段属性值
ATCCOR EQU 9eh ;存在的可执行可读一致代码段属性值
DSEG SEGMENT USE16 ;16位数据段
GDT LABEL BYTE ;全局描述符表
DUMMY Desc <> ;空描述符
Code Desc <0ffffh,,,ATCE,,> ;代码段描述符
DataD Desc <0ffffh,0,,ATDW,,> ;源数据段描述符
DataE Desc <0ffffh,,,ATDW,,> ;目标数据段描述符
GDTLen = $-GDT ;全局描述符表长度
VGDTR PDesc <GDTLen-1,> ;伪描述符
Code_Sel = Code-GDT ;代码段选择子
DataD_Sel = DataD-GDT ;源数据段选择子
DataE_Sel = DataE-GDT ;目标数据段选择子
BufLen = 64 ;缓冲区字节长度
Buffer DB BufLen DUP(55h) ;缓冲区
DSEG ENDS ;数据段定义结束
ESEG SEGMENT USE16 ;16位数据段
Buffer2 DB BufLen DUP(0) ;缓冲区
ESEG ENDS ;数据段定义结束
SSEG SEGMENT PARA STACK ;16位堆栈段
DB 512 DUP (0)
SSEG ENDS ;堆栈段定义结束
;打开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
;字符显示宏指令的定义
EchoCh MACRO ascii
mov ah,2
mov dl,ascii
int 21h
ENDM
;16位偏移的段间直接转移指令的宏定义(在16位代码段中使用)
JUMP16 MACRO Selector,Offset
DB 0eah ;操作码
DW Offset ;16位偏移量
DW Selector ;段值或段选择子
ENDM
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
mov WORD PTR DataD.BaseL,ax
mov BYTE PTR DataD.BaseM,dl
mov BYTE PTR DataD.BaseH,dh
;设置目标数据段描述符
mov ax,ESEG
mul bx
mov WORD PTR DataE.BaseL,ax
mov BYTE PTR DataE.BaseM,dl
mov BYTE PTR DataE.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,DataD_Sel
mov ds,ax ;加载源数据段描述符
mov ax,DataE_Sel
mov es,ax ;加载目标数据段描述符
cld
lea esi,Buffer
lea edi,Buffer2 ;设置指针初值
mov ecx,BufLen/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 ax,ESEG
mov es,ax
mov di,OFFSET Buffer2
cld
mov bp,BufLen/16
NextLine: mov cx,16
NextCh: mov al, es:[di]
inc di
push ax
shr al,4
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
cmp al,10
jae Over10
add al,'0'
ret
Over10:
add al,'A'-10
ret
ToASCII ENDP
CSEG ENDS ;代码段结束
END Start
9.3 保护模式下的中断程序设计
在响应中断时,CPU根据中断类型号执行对应的处理程序,把中断类型号作为中断描述符表IDT中描述符的索引,取得一个描述符(中断门),从描述符中得到中断处理程序的入口地址。中断描述符表寄存器IDTR指示IDT在内存中的位置和大小。
1. 中断处理程序
在程序的数据段DSEG中,定义了一个IDT,其中包括129个门描述符(IDT00~IDT80)。本实验中编写了3个中断处理程序:
(1) IRQ0Handler:中断类型为20h,处理来自于8259的定时中断,每秒执行18.2次。
(2) IRQ1Handler:中断类型为21h,处理来自于8259的键盘中断,键盘上的按键动作产生键盘中断。
(3) UserIntHandler:中断类型为80h,处理由int 80h指令所产生的软件中断。
中断处理程序位于32位代码段中,在GDT中为它定义了一个段描述符,代码段的选择符(Code32_Sel)保存在中断门中。
2. 中断类型
系统中有2片8259,主片8259处理IRQ0~IRQ7,从片8259处理IRQ8~IRQ15。在实模式下,DOS操作系统将IRQ0~IRQ7的中断类型设为08h~0FH,IRQ8~IRQ15的中断类型设为70h~77H。在保护模式下,08h~0FH类型号由CPU使用,所以本实验将IRQ0~IRQ7的中断类型设为20H~27H。需要对8259进行编程,来设定主片8259的ICW2。
对8259初始化时,必须对ICW1~ICW4全部设置。
进入保护模式后,调用Init8259A设置主片8259、从片8259的ICW1~ICW4,中断屏蔽寄存器;在返回实模式前,调用SetRealmode8259A恢复8259的设置。
3. 屏幕缓冲区
程序设置了一个段描述符用于访问屏幕缓冲区,屏幕缓冲区位于内存000B8000H处,屏幕上的每个字符在缓冲区占2个字节,第1个字节存放字符的ASCII码,第2个字节存放字符的属性(前景颜色、背景颜色)。
屏幕一共有25行、每一行80个字符,位置(x,y)所对应的缓冲区地址为:
000B8000h + (y * 80 + x) * 2 (x=0-24, y=0-79)
描述符中,基地址设为000B8000h,将其选择符DataV_Sel赋给GS。GS:[(y * 80 + x) * 2]对应于位置(x,y)所在的字符,GS:[(y * 80 + x) * 2 + 1]对应于该字符的显示属性。
4. 执行过程
中断处理程序执行时,必须要用到堆栈段,因此,程序将SS设为DataP_Sel,与数据段共用一个选择符。
中断程序所实现的功能为:
(1) IRQ0Handler程序改变屏幕上(0,70)位置的字符,程序执行时,该位置的字符不停地改变;
(2) IRQ1Handler程序改变屏幕上(1,70)位置的字符,有键盘输入时,该位置的字符发生改变;输入的扫描码保存在inkey变量中;
(3) UserIntHandler在屏幕(2,70)位置显示一个字符“!”。在保护模式下,执行指令“int 80h”调用该程序。
IRQ0和IRQ1是来自于主片8259的硬件中断,在中断处理程序中必须执行EOI(End Of Interrupt)操作,向主片8259的20h端口发送数据20h。
输入Esc键时,Esc键的扫描码01H被保存在inkey中,使程序从保护模式的循环查询中退出。
进入保护模式之前,SS、SP和IDTR的值被保存在数据段中,回到实模式后,恢复这3个寄存器的值。
;程序清单: intrpt.asm(保护方式下的中断处理过程)
.386P
;存储段描述符结构类型定义
Desc STRUC
LimitL DW 0 ;段界限(BIT0-15)
BaseL DW 0 ;段基地址(BIT0-15)
BaseM DB 0 ;段基地址(BIT16-23)
Attributes DB 0 ;段属性
LimitH DB 0 ;段界限(BIT16-19)(含段属性的高4位)
BaseH DB 0 ;段基地址(BIT24-31)
Desc ENDS
;伪描述符结构类型定义(用于装入全局或中断描述符表寄存器)
PDesc STRUC
Limit DW 0 ;16位界限
Base DD 0 ;32位基地址
PDesc ENDS
;门描述符结构类型定义
Gate STRUC
OffsetL DW 0 ;32位偏移的低16位
Selector DW 0 ;选择符
DCount DB 0 ;双字计数
GType DB 0 ;类型
OffsetH DW 0 ;32位偏移的高16位
Gate ENDS
;存储段描述符类型值说明
ATDR EQU 90h ;存在的只读数据段类型值
ATDW EQU 92h ;存在的可读写数据段属性值
ATDWA EQU 93h ;存在的已访问可读写数据段类型值
ATCE EQU 98h ;存在的只执行代码段属性值
ATCER EQU 9ah ;存在的可执行可读代码段属性值
ATCCO EQU 9ch ;存在的只执行一致代码段属性值
ATCCOR EQU 9eh ;存在的可执行可读一致代码段属性值
DA_386IGate EQU 8Eh ;386 中断门类型值
DSEG SEGMENT USE16 ;16位数据段
GDT LABEL BYTE ;全局描述符表
DUMMY Desc <> ;空描述符
Code Desc <0ffffh,,,ATCER,,> ;代码段描述符
DataV Desc <0ffffh,,,ATDW,,> ;数据段描述符(屏幕缓冲区)
DataP Desc <0ffffh,,,ATDWA,,> ;数据段描述符
Code32 Desc <0ffffh,,,ATCER,40h,> ;代码段描述符
GDTLen = $-GDT ;全局描述符表长度
VGDTR PDesc <GDTLen-1,> ;伪描述符
; IDT
ALIGN 32
IDT LABEL BYTE
IDT_00_1F Gate 32 dup (<offset SpuriousHandler,Code32_Sel,0,DA_386IGate,0>)
IDT_20 Gate 1 dup (<offset IRQ0Handler,Code32_Sel,0,DA_386IGate,0>)
IDT_21 Gate 1 dup (<offset IRQ1Handler,Code32_Sel,0,DA_386IGate,0>)
IDT_22_7F Gate 94 dup (<offset SpuriousHandler,Code32_Sel,0,DA_386IGate,0>)
IDT_80 Gate 1 dup (<offset UserIntHandler,Code32_Sel,0,DA_386IGate,0>)
IDTLen = $-IDT ;中断描述符表长度
VIDTR PDesc <IDTLen-1,> ;伪描述符
_SavedSP dw 0
_SavedSS dw 0
_SavedIDTR dd 0 ; 用于保存 IDTR
dd 0
DSEG ENDS ;数据段定义结束
PSEG SEGMENT PARA STACK ;保护模式下使用的数据段
db 512 dup (0)
TopOfStack LABEL BYTE
inkey db 0
_tmp db 0
_SavedIMREG_M db 0 ; 中断屏蔽寄存器值
_SavedIMREG_S db 0 ;
PSEG ENDS
SSEG SEGMENT PARA STACK ;16位堆栈段
DB 512 DUP (0)
SSEG ENDS ;堆栈段定义结束
Code_Sel = Code-GDT ;16位代码段选择符
DataV_Sel = DataV-GDT ;屏幕缓冲区数据段选择符
DataP_Sel = DataP-GDT ;PSEG数据段选择符
Code32_Sel = Code32-GDT ;32位代码段段选择符
;打开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位偏移的段间直接转移指令的宏定义(在16位代码段中使用)
JUMP16 MACRO Selector,Offset
DB 0eah ;操作码
DW Offset ;16位偏移量
DW Selector ;段值或段选择符
ENDM
CSEG SEGMENT USE16 ;16位代码段
ASSUME CS:CSEG,DS:DSEG
Start PROC
mov ax,DSEG
mov ds,ax
mov _SavedSP,ss
mov _SavedSS,sp
;准备要加载到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
;准备要加载到IDTR的伪描述符
mov ax,SEG IDT
mov bx,16
mul bx
add ax,OFFSET IDT ;计算并设置基地址
adc dx,0 ;界限已在定义时设置好
mov WORD PTR VIDTR.Base,ax
mov WORD PTR VIDTR.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
;设置代码段描述符(32位代码段)
mov ax,seg SpuriousHandler
mul bx
mov WORD PTR Code32.BaseL,ax ;代码段开始偏移为0
mov BYTE PTR Code32.BaseM,dl ;代码段界限已在定义时设置好
mov BYTE PTR Code32.BaseH,dh
;设置数据段描述符(屏幕显示缓冲区)
mov ax,8000h
mov dx,000BH
mov WORD PTR DataV.BaseL,ax
mov BYTE PTR DataV.BaseM,dl
mov BYTE PTR DataV.BaseH,dh
;设置数据段描述符(保护模式下使用的数据段)
mov ax,PSEG
mul bx ;计算并设置数据段基址
mov WORD PTR DataP.BaseL,ax
mov BYTE PTR DataP.BaseM,dl
mov BYTE PTR DataP.BaseH,dh
; 保存 IDTR
sidt QWORD PTR _SavedIDTR
;加载GDTR
lgdt QWORD PTR VGDTR
cli ;关中断
EnableA20 ;打开地址线A20
lidt QWORD PTR VIDTR
;切换到保护方式
mov eax,cr0
or eax,1
mov cr0,eax
;清指令预取队列,并真正进入保护方式
JUMP16 Code_Sel,<OFFSET Virtual>
ALIGN 32
Virtual: ;现在开始在保护方式下运行
mov ax,DataV_Sel
mov gs,ax ;GS指向屏幕显示缓冲区
mov ax,DataP_Sel
mov ds,ax ;DS指向PSEG
mov ss,ax ;SS指向PSEG
mov sp,offset TopOfStack
; 保存中断屏蔽寄存器(IMREG)值
in al,21h
mov _SavedIMREG_M,al
in al,0A1h
mov _SavedIMREG_S,al
call Init8259A
int 080h
sti
WaitLoop:
mov al,inkey
mov _tmp,al
cmp _tmp,1
jnz WaitLoop
cli
call SetRealmode8259A
;切换回实模式
mov eax,cr0
and al,11111110b
mov cr0,eax
;清指令预取队列,进入实方式
JUMP16 <SEG Real>,<OFFSET Real>
Init8259A:
mov al,011h
out 020h,al ; 主8259,ICW1.
call io_delay
out 0A0h,al ; 从8259,ICW1.
call io_delay
mov al,020h ; IRQ0 对应中断向量 0x20
out 021h,al ; 主8259,ICW2.
call io_delay
mov al,028h ; IRQ8 对应中断向量 0x28
out 0A1h,al ; 从8259,ICW2.
call io_delay
mov al,004h ; IR2 对应从8259
out 021h,al ; 主8259,ICW3.
call io_delay
mov al,002h ; 对应主8259的 IR2
out 0A1h,al ; 从8259,ICW3.
call io_delay
mov al,001h
out 021h,al ; 主8259,ICW4.
call io_delay
out 0A1h,al ; 从8259,ICW4.
call io_delay
mov al,11111100b ; 仅仅开启定时器、键盘中断
out 021h,al ; 主8259,OCW1.
call io_delay
mov al,11111111b ; 屏蔽从8259所有中断
out 0A1h,al ; 从8259,OCW1.
call io_delay
ret
SetRealmode8259A:
mov al,011h
out 020h,al ; 主8259,ICW1.
call io_delay
out 0A0h,al ; 从8259,ICW1.
call io_delay
mov al,08h ; IRQ0 对应中断向量 0x20
out 021h,al ; 主8259,ICW2.
call io_delay
mov al,70h ; IRQ8 对应中断向量 0x28
out 0A1h,al ; 从8259,ICW2.
call io_delay
mov al,004h ; IR2 对应从8259
out 021h,al ; 主8259,ICW3.
call io_delay
mov al,002h ; 对应主8259的 IR2
out 0A1h,al ; 从8259,ICW3.
call io_delay
mov al,001h
out 021h,al ; 主8259,ICW4.
call io_delay
out 0A1h,al ; 从8259,ICW4.
call io_delay
mov al,_SavedIMREG_M ; 恢复中断屏蔽寄存器(IMREG)的原值
out 021h,al ;
call io_delay
mov al,_SavedIMREG_S ; 恢复中断屏蔽寄存器(IMREG)的原值
out 0A1h,al ;
call io_delay
ret
io_delay:
nop
nop
nop
nop
ret
Real: ;现在又回到实方式
DisableA20
mov ax,DSEG
mov ds,ax
mov ss,_SavedSP
mov sp,_SavedSS
lidt QWORD PTR _SavedIDTR
sti
mov ax,4c00h
int 21h
Start ENDP
CSEG ENDS ;代码段定义结束
CSEG32 SEGMENT USE32
ASSUME CS:CSEG32,DS:PSEG
IRQ0Handler:
inc byte ptr gs:[((80 * 0 + 70) * 2)] ; 屏幕第 0 行,第 70 列。
mov al,20h
out 20h,al ; 发送EOI到主8259
iretd
IRQ1Handler:
in al,60h
mov inkey,al
inc byte ptr gs:[((80 * 1 + 70) * 2)] ; 屏幕第 1 行,第 70 列。
mov al,20h
out 20h,al ; 发送EOI到主8259
iretd
UserIntHandler:
mov ah,0Ch ; 0000 黑底 1100 红字
mov al,'I'
mov gs:[((80 * 2 + 70) * 2)],ax ; 屏幕第 2 行,第 70 列。
iretd
SpuriousHandler:
iretd
CSEG32 ENDS
END Start
9.3 实验题:保护模式综合实验
在intrpt.asm的基础上,扩充其GDT、IDT表,修改中断类型号,显示键盘按键的ASCII码等。
要求:
1. 在保护模式下使用独立的堆栈段(与数据段区分开);
2. 设置一个新的中断类型81h,在保护模式下,执行“int 81h”将屏幕内容清空;
3. 将主片8259的IRQ0~IRQ7中断类型号修改为50h~57h,从片IRQ8~IRQ15的中断类型号修改为58h~5fh。
4. 键盘上有键被按下时,在屏幕上显示出ASCII码。表9-1列出了键盘上主要按键的扫描码与ASCII字符的对应关系。
表9-1 扫描码与ASCII字符对应关系
扫描码
ASCII字符
扫描码
ASCII字符
扫描码
ASCII字符
扫描码
ASCII字符
02H
1
10H
q
1EH
a
2CH
z
03H
2
11H
w
1FH
s
2DH
x
04H
3
12H
e
20H
d
2EH
c
05H
4
13H
r
21H
f
2FH
v
06H
5
14H
t
22H
g
30H
b
07H
6
15H
y
23H
h
31H
n
08H
7
16H
u
24H
j
32H
m
09H
8
17H
i
25H
k
33H
,
0AH
9
18H
o
26H
l
34H
.
0BH
0
19H
p
27H
;
35H
/
0CH
-
1AH
[
28H
‘
0DH
=
1BH
]
29H
`
- 实验9 保护模式编程基础
- 实验9 保护模式编程基础
- 保护模式实验一
- 保护模式实验环境搭建
- 保护模式基础
- 保护模式--基础
- 保护模式编程<五>
- 保护模式编程、六
- 保护模式编程
- 保护模式编程实例
- 保护模式编程学习心得
- 保护模式下编程
- x86 保护模式编程
- 保护模式编程初始化
- 【学习】【保护模式编程、一】
- 【学习】【保护模式编程、二】
- 【学习】【保护模式编程、三】
- 【学习】【保护模式编程、四】
- 类的静态成员变量
- 用Spring AOP实现开发中松散耦合
- SQL 2K 基礎
- 安装 jBPM 的 Eclipse 开发插件
- 在XHTML1.1 Strict Doctype下xhtml+xml伺服的页面中投放阿里妈妈广告代码的方法
- 实验9 保护模式编程基础
- Cocoa处理消息的方法:Delegate
- 实现基于Spring框架应用的权限控制系统
- ASP.NET跨应用程序进行登录的解决
- 正确使用gettext来翻译Wordpress主题
- 开始学习grails
- 用C#对Illustrator矢量图形软件进行编程之2
- PKU 1707 Sum of powers 解题报告
- XML序列化与反序列化 整理文档 - Kevin Cheng