代码改变世界

Chapter3 保护模式-a

2013-05-03 18:52  fingertouch  阅读(277)  评论(0编辑  收藏  举报

先贴代码:

; ==========================================
; pmtest1.asm
; 编译方法:nasm pmtest1.asm -o pmtest1.bin
; ==========================================

%include	"pm.inc"	; 常量, 宏, 以及一些说明

org	07c00h
	jmp	LABEL_BEGIN

[SECTION .gdt]
; GDT
;                              段基址,       段界限     , 属性
LABEL_GDT:	   Descriptor       0,                0, 0           ; 空描述符
LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段
LABEL_DESC_VIDEO:  Descriptor 0B8000h,           0ffffh, DA_DRW	     ; 显存首地址
; GDT 结束

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

; GDT 选择子
SelectorCode32		equ	LABEL_DESC_CODE32	- LABEL_GDT
SelectorVideo		equ	LABEL_DESC_VIDEO	- LABEL_GDT
; END of [SECTION .gdt]

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

	; 初始化 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

	; 为加载 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,
					; 并跳转到 Code32Selector:0  处
; END of [SECTION .s16]


[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS	32]

LABEL_SEG_CODE32:
	mov	ax, SelectorVideo
	mov	gs, ax			; 视频段选择子(目的)

	mov	edi, (80 * 11 + 79) * 2	; 屏幕第 11 行, 第 79 列。
	mov	ah, 0Ch			; 0000: 黑底    1100: 红字
	mov	al, 'P'
	mov	[gs:edi], ax

	; 到此停止
	jmp	$

SegCode32Len	equ	$ - LABEL_SEG_CODE32
; END of [SECTION .s32]

;新增代码
times    382-($-$$)    db    0
dw    0xaa55

 

其中代码最底部的两行代码为新增代码,如果使用书中的代码进行编译(步骤如下):

1. bximage一个a.img的软盘

2. nasm -o pmtest1.bin pmtest1.asm

3. dd if=pmtest1.bin of=a.img bs=512 count=1 conv=notrunc

4. 启动Bochs

5. 运行程序(c键回车)

将会提示:[BIOS] error,No Boot Device

这是什么原因呢?这主要是因为我们在第二步中产生的pmtest1.bin文件超出512B的原因,所以在拷贝的时候发生了截断,为了让其保持在512B以内,并且最后是以AA55结尾的,我们使用了新增部分,其中的382是这么来的:

第2步产生的pmtest1.bin文件大小是640B,比512要大128B,本来在代码最后处应该是

times    510-($-$$)    db    0

 但是为了保证文件的大小是512B,所以使用510-128=382来填充,这样写入到a.img中,再运行程序就不会出错了。

当然如果nasm编译后的文件太大,超过1KB以上,那么我们就不能使用这种直接引导的方式来运行程序了,这时候我们有两种方法:

1. 写一个引导扇区,让其可以读取我们的程序并运行它。

2. 借助别的东西,比如DOS,我们可以将程序编译成COM文件,然后行DOS来执行它。

所以在第三章以后(包含第三章)我都是通过DOS来执行我们的程序的。