操作系统开发小试-保护模式引导程序(续)

+------------------------------------------------------------+
操作系统开发小试-保护模式引导程序(续)
+------------------------------------------------------------+
+
+1.开发语言:ASM(工具:NASM)
+2.虚拟环境:Virtual PC
+3.应用工具:WinHex Ver11.2
=====================================================

%include "pm.inc"
;%define _BOOT_DEBUG_
%ifdef _BOOT_DEBUG_
org 00100h
%else
org 07c00h
%endif

jmp begin_boot ; 跳过其它的数据,跳转到引导程序的开始处

[SECTION .gdt]
;gdt
LABEL_DESC_NULL: Descriptor 0, 0, 0
LABEL_DESC_NORMAL: Descriptor 0, 0xFFFF, DA_DRW
LABEL_DESC_CODE16: Descriptor 0, 0xFFFF, DA_C
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_C + DA_32
LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW
LABEL_DESC_VIDEO: Descriptor 0xB8000, 0xFFFF, DA_DRW

gdtr dw $ - LABEL_DESC_NULL
dd 0x00

SelectorNormal equ LABEL_DESC_NORMAL - LABEL_DESC_NULL
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_DESC_NULL
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_DESC_NULL
SelectorData equ LABEL_DESC_DATA - LABEL_DESC_NULL
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_DESC_NULL

[SECTION .data1] ; 数据段
ALIGN 32
[BITS 32]
LABEL_DATA:
PMMessage: db "In Protect Mode now. ^-^", 0 ; 进入保护模式后显示此字符串
OffsetPMMessage equ PMMessage - $$
DataLen equ $ - LABEL_DATA
; END of [SECTION .data1]

[SECTION .s16]
[BITS 16]
print_mesg: ; 打印信息调用
mov ah, 0x13 ; 使用中断10h的功能13,在屏幕上写一个字符串
mov al, 0x00 ; 决定调用函数后光标所处的位置
mov bx, 0x0007 ; 设置显示属性
mov cx, 0x20 ; 在此字符串长度为32
mov dx, 0x0000 ; 光标的起始行和列
int 0x10
ret

get_key: ;等待按键
mov ah, 0x00
int 0x16 ; Get_key使用中断16h的功能0,读取下一个字符
ret

clrscr: ; 清屏
mov ax, 0x0600 ; 使用中断10h的功能6,实现卷屏,如果al=0则清屏
mov cx, 0x0000 ; 清屏
mov dx, 0x174f ; 卷屏至23,79
mov bh, 0 ; 使用颜色0来填充
int 0x10
ret

SwitchMessage: db "Switching to Protected Mode... "
SwitchOverMessage: db "From Protect To Real Mode ... "

begin_boot: ; 引导程序开始
mov ax, cs ; 设置段寄存器
mov ds, ax
mov es, ax

mov [LABEL_GO_BACK_TO_REAL+3], ax

call clrscr
mov ax, 0xb800
mov gs, ax ; 使gs指向显示内存
mov word [gs:0], 0x641 ; 在实模式下显示一个棕色的A
call get_key

mov bp, SwitchMessage ; 提供字符串地址
call print_mesg
call get_key
call clrscr

; 初始化 16 位代码段描述符
mov ax, cs
movzx eax, ax
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


; 设置GDT物理基地址
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_DESC_NULL
mov dword [gdtr+2], eax

; 加载GDT
lgdt [gdtr]

; 关中断
cli

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

; 进入保护模式
mov eax, cr0
or al, 1 ; 设置保护模式位
mov cr0, eax

; 跳至32位代码
jmp SelectorCode32:0

LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax

in al, 92h ; ┓
and al, 11111101b ; ┣ 关闭 A20 地址线
out 92h, al ; ┛

sti ; 开中断

call get_key
call clrscr
mov bp, SwitchOverMessage ; 提供字符串地址
call print_mesg

[SECTION .s32]
[BITS 32] ; 以32位方式编译
LABEL_SEG_CODE32:
mov ax, SelectorVideo ; 使gs指向显存
mov gs, ax
mov ax, SelectorData
mov ds, ax ; 数据段选择子

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

DispStr32:
mov ah, 0Ch ; 0000: 黑底 1100: 红字
xor esi, esi
xor edi, edi
mov esi, OffsetPMMessage ; 源数据偏移
mov edi, (80 * 10 + 0) * 2 ; 目的数据偏移
cld
.1:
lodsb
test al, al
jz .2
mov [gs:edi], ax
add edi, 2
jmp .1
.2:

jmp SelectorCode16:0

SegCode32Len equ $ - LABEL_SEG_CODE32

[SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:
; 跳回实模式:
mov ax, SelectorNormal
mov ds, ax
mov es, ax
mov gs, 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

评论

此博客中的热门博文

如何解决在Delphi2009中添加pas组件的问题

在Delphi中操作Sap对象造成内存增长的原因

杀死团队的七种武器(转)