这几天还是在学习《自己动手写操作系统》,终于将保护模式了了。
上来贴上代码:
%include "pm.inc"
org0100h
xchgbx,bx
jmpSTART
[SECTION .gdt]
GDT_DEC:Descriptor0,0,0
CODE32_DEC:Descriptor0,Code32SegLen-1,DA_32+DA_CE
VIDEO_DEC:Descriptor0b8000h,0ffffh,DA_DRW
DATA32_DEC:Descriptor0,Data32SegLen-1,DA_DRW
STACK32_DEC:Descriptor0,StackTop,DA_32+DA_DRW
EXTRA_DEC:Descriptor050000h,0ffffh,DA_DRW
CODE16_DEC:Descriptor0,0ffffh,DA_CE
NORMAL_DEC:Descriptor0,0ffffh,DA_DRW
GdtLenequ$ - GDT_DEC
GdtptrdwGdtLen-1;Length of GDT
dd0;base of GDT
SelectorCode32equCODE32_DEC- GDT_DEC
SelectorVideoequVIDEO_DEC- GDT_DEC
SelectorDataequDATA32_DEC - GDT_DEC
SelectorStackequSTACK32_DEC- GDT_DEC
SelectorExtraequEXTRA_DEC- GDT_DEC
SelectorCode16equCODE16_DEC- GDT_DEC
SelectorNormalequNORMAL_DEC- GDT_DEC
[SECTION .s16]
[BITS 16]
START:
movax,cs
movds,ax
movss,ax
moves,ax
movsp,100h
mov[BACK_TO_REAL+3],ax
mov[RealModeSp],sp
;load Code32Segment Base
xoreax,eax
movax,cs
shleax,4
addeax,CODE32_SEG
mov [CODE32_DEC+2],ax
shreax,16
mov[CODE32_DEC+4],al
mov[CODE32_DEC+7],ah
;load data segment
xoreax,eax
movax,ds
shleax,4
addeax,DATA32_SEG
mov[DATA32_DEC+2],ax
shreax,16
mov[DATA32_DEC+4],al
mov[DATA32_DEC+7],ah
;load stack segment base
xoreax,eax
movax,ss
shleax,4
addeax,STACK_SEG
mov[STACK32_DEC+2],ax
shreax,16
mov[STACK32_DEC+4],al
mov[STACK32_DEC+7],ah
;load code16 segment base
xoreax,eax
movax,cs
shleax,4
addeax,CODE16_SEG
mov[CODE16_DEC+2],ax
shreax,16
mov[CODE16_DEC+4],al
mov[CODE16_DEC+7],ah
;load GDT Base
xoreax,eax
movax,cs
shleax,4
addeax,GDT_DEC
mov [Gdtptr+2],eax
lgdt[Gdtptr]
cli
inal,92h
oral,02h
out92h,al
moveax,cr0
oreax,01h
movcr0,eax
jmpdwordSelectorCode32:0 ;Enter to Protected mode!
ENTER_REAL_MODE:
movax,cs
movds,ax
moves,ax
movss,ax
movfs,ax
movgs,ax
movsp,[RealModeSp]
inal,92h
andal,11111101b
out92h,al
sti
;call BIOS int 10h to test if back to real
movcx,22
movbh,0
movbl,89h
movdx,1000h
movbp,BackRealMeg
movah,13h
moval,01h
int10h
;back to dos
movax,4c00h
int21h
[SECTION .p16]
ALIGN 32
[BITS 16]
CODE16_SEG:
movax,SelectorNormal
movds,ax
movss,ax
movgs,ax
movfs,ax
moves,ax
moveax,cr0
andeax,0feh
movcr0,eax
BACK_TO_REAL:
jmp0:ENTER_REAL_MODE
Code16SegLenequ$ - $$
[SECTION .s32]
ALIGN32
[BITS 32]
DATA32_SEG:
Message:db "Welcome to Protected Mode!",0
MessageLenequ $ - Message
offMessage equ Message - $$
RealModeSpdw0
Letters:db "ABCDEFGHIJKLMNOPQRSTUVWXYZ",0
offLettersequLetters -$$
BackRealMeg: db "Welcome back to real!\n"
Data32SegLenequ $ - $$
[SECTION .stack]
ALIGN32
[BITS 32]
STACK_SEG:
times 512 db 0
StackTop equ$ - STACK_SEG - 1
[SECTION .s32]
[BITS 32]
CODE32_SEG:
movax,SelectorVideoto
movgs,ax
movax,SelectorData
movds,ax
movax,SelectorStack
movss,ax
movesp,StackTop
movax,SelectorExtra
moves,ax
callDispMessage
callDispReturn
callReadFromExtraSeg
callWriteToExtraSeg
callReadFromExtraSeg
jmpSelectorCode16:0
DispMessage:
movah,0ch
movesi,offMessage
movedi,(80*12+20)*2
movecx,MessageLen
.loop:
moval,[esi]
mov[gs:edi],ax
addedi,2
incesi
loop .loop
ret
ReadFromExtraSeg:
xoresi,esi
movecx,08h
.loop:
moval,[es:esi]
callDispAlAsNum
incesi
loop .loop
callDispReturn
ret
DispAlAsNum:
pushecx
pushedx
movecx,02h
movdl,al
shral,4
movah,0ch
.loop:
andal,0fh
cmpal,09h
ja.letter
addal,'0'
jmp.Disp
.letter:
subal,0ah
addal,'A'
.Disp:
mov[gs:edi],ax
moval,dl
addedi,2
loop.loop
addedi,2
popedx
popecx
ret
DispReturn:
pusheax
pushebx
moveax,edi
movbl,160
divbl
andeax,0ffh
inceax
mulbl
movedi,eax
popebx
popeax
ret
WriteToExtraSeg:
pushesi
pushedi
xoresi,esi
xoredi,edi
movesi,offLetters
cld
.loop:
lodsb
testal,al
jz.ok
mov[es:edi],al
incedi
loop.loop
.ok:
popedi
popesi
ret
Code32SegLenequ$ - $$
然后运行结果图:
这个程序先从实模式进入保护模式,然后从附加段中读数据并输出,再从数据段向附加段写数据,然后输出。最后返回实模式。
刚开始时,没注意,还是利用org 0x7c00开头,直接从该软驱启动,但是提示找不到启动设备。然后利用Hex Edit查看,发现 510 511 单元不是55 aa而是00 00 ,再查看源代码,可以发现这块已经被Stack占用,也就是说,我们得程序已经超过了512B,那么,只好利用其他东西(如Freedos)来做引导.最后将改程序放入其一个软驱中。在DOS中运行这个程序。
还有就是,在DOS中如果程序出问题了该怎么办,我一开始想到得是Debug,但是遗憾得是没有这个命令。所以只好另图他径。首先在Bochs配置文件中添加magic_break : enabled=1,然后在程序中利用xchg bx,bx来设置断点。当你运行改程序时,在这里会自动将控制权交给Bochs,然后你就可以在Bochs中调试了。
再后呢就是关于从保护模式跳入实模式得步骤:
1. 关中断, 因为一开始中断就关掉了, 这步可以省略
2. 将程序从一个32位的代码段转移到16位的代码段, 这个代码段的段界限必须是64KB, 即FFFFh, 就是程序中的
SelectorCode16描述的那个段
这个的作用是刷新CS寄存器, 使它符合实模式下cs寄存器的要求
3. 刷新数据段的寄存器, 包括DS, ES, FS, GS, SS, 使得它们也符合实模式下的要求, 就是mov ax,
SelectorNormal的作用, SelectorNormal的要求是:
Limit = 64KB ( 0FFFFh )
Byte granular = 0 ( G = 0 )
Expand up ( E = 0 )
Writable ( W = 1 )
Present ( P = 1 )
Base = any value
也就是说, SelectorNormal描述的段要完全符合实模式下的数据段的要求
4. 清Cr0的PE位, 真正的转换到实模式, 需要注意的是SelectorCode16描述的那个段中的代码仍然是保护模式下的, 只不过是16
位的代码
只有当PE位清0的时候, 才真正的转换到实模式, 这个时候, 需要有一个跳转, 真正的跳转到实模式下的代码段, 而这个跳转的寻址方式是实
模式寻址方式
5. 经过第4步的关键跳转, CS被更新成了真正的实模式下的段地址, 这个时候, 需要重新刷新数据段寄存器, 使他们工作在实模式下,
这些数据寄存器包括上述提到的所有的段寄存器, 即DS, ES, FS, GS, SS, 如果你不用它们的话, 就直接赋值为0也是可以的
6. 开中断, 这步完成之后, 就完全完成了保护模式到实模式的切换
此时,你可以调用dos中断返回dos操作系统, 书上就是这么做的
大小: 17.9 KB
1
顶
0
踩
分享到:
2012-04-07 14:54
浏览 1040
评论