pmtest2.asm

我们从实模式进入保护模式时直接用一个跳转就可以了,但是返回的时候却稍稍复杂一些。因为在准备结束保护模式回到实模式之前,需要加载一个合适的描述符选择子到有关段寄存器,以使对应段描述符高速缓冲寄存器中含有合适的段界限和属性。而且,我们不能从32位代码段返回实模式,只能从16位代码段中返回。这是因为无法实现从32位代码段返回时cs高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)。所以,在这里,我们新增一个Normal描述符(代码3.4第15行)。在返回实模式之前把对应选择子SelectorNormal加载到ds、es和ss。具体看[SECTION .s16code]

;pmtest2.asm

%include "pm.inc"
org 0100h
jmp LABEL_BEGIN

[SECTION .gdt]
;								段基址,段界限,属性
LABEL_GDT:			Descriptor 0,0,0
LABEL_DESC_NORMAL:	Descriptor 0,0ffffh,DA_DRW;NORMAL描述符
LABEL_DESC_CODE32:	Descriptor 0,SegCode32Len-1,DA_C+DA_32;非一致代码段
LABEL_DESC_CODE16:	Descriptor 0,0ffffh,DA_C
LABEL_DESC_DATA:	Descriptor 0,DataLen-1,DA_DRW;Data
LABEL_DESC_STACK:	Descriptor 0,TopOfStack,DA_DRWA+DA_32;Stack,32位
LABEL_DESC_TEST:	Descriptor 0500000h,0ffffh,DA_DRW;;一个以5MB为基址的段,用于测试大地址内存的读写
LABEL_DESC_VIDEO:	Descriptor 0B8000h,0ffffh,DA_DRW;显存首地址
;GDT结束

GdtLen	equ	$-LABEL_GDT
GdtPtr	dw	GdtLen-1	;GDT界限
		dd	0			;GDT基址

;GDT选择子
SelectorNormal	equ	LABEL_DESC_NORMAL-LABEL_GDT
SelectorCode32	equ LABEL_DESC_CODE32-LABEL_GDT
SelectorCode16	equ LABEL_DESC_CODE16-LABEL_GDT
SelectorData	equ LABEL_DESC_DATA-LABEL_GDT
SelectorStack	equ LABEL_DESC_STACK-LABEL_GDT
SelectorTest	equ LABEL_DESC_TEST-LABEL_GDT
SelectorVideo	equ LABEL_DESC_VIDEO-LABEL_GDT
;END OF [SECTION .gdt]

[SECTION .data1];数据段
ALIGN 32
[BITS 32]
LABEL_DATA:
SPValueInRealMode	dw	0
;字符串
PMMessage:	db	"In.Protext.Mode.Now.^-^",0	;保护模式中显示
OffsetPMMessage	equ	PMMessage-$$
StrTest:	db	"ABCDEFGHIJKLMNOPQRSTUVWXYZ",0
OffsetStrTest	equ StrTest-$$
DataLen		equ	$-LABEL_DATA
;END OF [SECTION .data1]

;全局堆栈段
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
	times	512 db 0
	TopOfStack	equ $-LABEL_STACK-1
;END OF [SECTION .gs]

[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
	mov ax,cs
    mov ds,ax
	mov es,ax
	mov ss,ax
	mov sp,0100h
	mov [LABEL_GO_BACK_TO_REAL+3],ax

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

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

	; 初始化数据段描述符
    xor eax, eax
    mov ax, ds
    shl eax, 4
    add eax, LABEL_DATA
    mov word [LABEL_DESC_DATA + 2], ax
    shr eax, 16
    mov byte [LABEL_DESC_DATA + 4], al
    mov byte [LABEL_DESC_DATA + 7], ah

	;初始化堆栈段描述符  
    xor eax, eax  
    mov ax, ds  
    shl eax, 4  
    add eax, LABEL_STACK  
    mov word [LABEL_DESC_STACK + 2], ax  
    shr eax, 16  
    mov byte [LABEL_DESC_STACK + 4], al  
    mov byte [LABEL_DESC_STACK + 7], ah  
	
	;为加载gdtr做准备
	xor eax,eax
	mov ax,ds
	shl eax,4
	add eax,LABEL_GDT ;eax <-- gdt基地址
	mov dword [GdtPtr+2],eax ;[GdtPtr+2] <-- gdt基地址

	;加载gdtr
	lgdt [GdtPtr]

	;关中断
	cli

	;打开地址线A20
	in al,92h
	or al,00000010b
	out 92h,al

	;准备切换到保护模式
	mov eax,cr0
	or eax,1
	mov cr0,eax

	;进入保护模式
	jmp dword SelectorCode32:0
	;把SelectorCode32装入cs,并转到SelectorCode32:0处

LABEL_REAL_ENTRY:
	mov ax,cs
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov sp,[SPValueInRealMode]

	in al,92h
	and al,11111101b ;关闭A20地址线
	out 92h,al
	
	sti;开中断
	mov ax,4c00h
	int 21h;回到DOS

;END OF [SECTION .s16]

[SECTION .s32]
[BITS 32]
LABEL_SEG_CODE32:
	mov ax,SelectorData
	mov ds,ax		;数据段选择子
	mov ax,SelectorTest
	mov es,ax		;测试段选择子,es指向新增的基址为5MB内存的段
	mov ax,SelectorVideo
	mov gs,ax		;视频段选择子,gs指向显存
	mov ax,SelectorStack
	mov ss,ax		;堆栈段选择子
	mov esp,TopOfStack

	;显示字符串
	mov ah,0Ch	;0000黑底 1100红字
	xor esi,esi
	xor edi,edi
	mov esi,OffsetPMMessage	;源数据偏移
	mov edi,(80*10+0)*2		;目的数据偏移,屏幕第10行第0列
	cld
.1:
	lodsb
	test al,al
	jz	.2
	mov [gs:edi],ax
	add edi,2
	jmp .1
.2:	;显示完毕
	call DispReturn
	call TestRead
	call TestWrite
	call TestRead
	;到此停止
	jmp SelectorCode16:0

;------------------------------
TestRead:
	xor esi,esi
	mov ecx,8
.loop:
	mov al,[es:esi];新增的以5MB为基址的段开始处
	call DispAL
	inc esi
	loop .loop
	call DispReturn
	ret
;TestRead结束-------------------

;-------------------------------
TestWrite:
	push esi
	push edi
	xor esi,esi
	xor edi,edi
	mov esi,OffsetStrTest	;源数据偏移
	cld
.1:
	lodsb
    test al,al
    jz  .2
    mov [es:edi],al
	inc edi
    jmp .1
.2:
	pop edi
	pop esi
	ret
;TestWrite结束-------------------

;--------------------------------
;使用16进制显示AL中的数字
;默认地:
;	数字已经存在AL中
;	edi始终指向要显示的下一个字符的位置
;被改变的寄存器:
;	edi,ax
;--------------------------------
DispAL:
	push edx
	push ecx

	mov ah,0Ch
	mov dl,al
	shr al,4
	mov ecx,2
.begin:
	and al,01111b
	cmp al,9	;01001b
	ja .1
	add al,'0'
	jmp .2
.1:
	sub al,0Ah
	add al,'A'
.2:
	mov [gs:edi],ax
	add edi,2
	mov al,dl
	loop .begin
	add edi,2

	pop edx
	pop ecx
	ret
;DispAL结束-----------------

;-------------------------------
DispReturn:
	push eax
	push ebx
	mov eax,edi
	mov bl,160
	div bl
	and eax,0FFh
	inc eax
	mov bl,160
    mul bl
    mov edi,eax

    pop ebx
    pop eax
    ret
;disreturn 结束------------------------------------------

SegCode32Len equ $-LABEL_SEG_CODE32

;END OF [SECTION .s32]

;从保护模式返回实模式需要用到一个16位的段
[SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:
	mov ax,SelectorNormal
	mov ds,ax
	mov es,ax
	mov fs,ax
	mov gs,ax
	mov ss,ax

	mov eax,cr0
	and al,11111110b
	mov cr0,eax
LABEL_GO_BACK_TO_REAL:
	jmp 0:LABEL_REAL_ENTRY;段地址会在程序开始处被设置成正确的值

Code16Len equ $-LABEL_SEG_CODE16
;END OF [SECTION .s16code]
nasm pmtest2.asm -o pmtest2.com
sudo mount -o loop pm.img /mnt/floppy
sudo cp pmtest2.com /mnt/floppy/
sudo umount /mnt/floppy
bochs -f bochsrc

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值