您的位置:首页 > 其它

自己动手写操作系统学习笔记

2010-04-20 11:10 281 查看
;
;保护模式的学习
;
;
;

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

[SECTION .gdt]

LABEL_GDT: Descriptor 0,0,0;空描述符,GDT中,必须有一个空描述符
LABEL_DESC_CODE32: Descriptor 0,SegCode32Len-1,DA_C+DA_32
LABEL_DESC_VIDEO: Descriptor 0B8000h,0ffffh,DA_DRW

GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen
dd 0

SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT ;这个地方真的很精彩,描述符的长度是八个字节。
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT ;而参看“选择子Selector”的格式,低三位是TI,RPL,高13位才是INDEX
;2^3刚好是8,这样,LABEL_DESC_CODE32 - LABEL_GDT得到的高十三位好就是
;LABEL_DESC_CODE32在GDT中的序号
;
;个人认为,选择子Selector的使用,就是为了让保护模式下的寻址和实模式下
;的寻址兼容。因为选择子的长度是16,我们还是能像在实模式下操作地址一样,
;只是在得到的地址实际上是保护模式下的地址。
;
;我想这也就是所谓的"对程序员编程来说,没有增加复杂性"的意义所在吧。

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

xor eax,eax ;这个地方CS中的是段地址,再加上LABEL_SEG_CODE32这个偏移地址
mov ax,cs ;即实模式地址计算方法:CS*16+LABEL_SEG_CODE32
shl eax,4 ;从而得到了LABEL_DESC_CODE32的物理地址
add eax,LABEL_SEG_CODE32 ;并将其保存到LABEL_DESC_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 ;完成了对LABEL_DESC_CODE32描述符的初始化

xor eax,eax ;
mov ax,ds ;
shl eax,4 ;将GDT的物理地址保存到GdtPtr的第三到第六字节中
add eax,LABEL_GDT ;为加载GDT到gdt寄存器中做准备
mov dword [GdtPtr+2],eax ;

lgdt [GdtPtr]

cli ;关实模式的中断,因为保护模式下的中断方式和实模式下不同。

in al,92h ;只有打开A20的地址线,才能访问大于1MB的地址空间
or al,00000010b ;也有其它办法打开A20地址线,对端口92h操作是常用的方法
out 92h,al ;

mov eax,cr0 ;cr0是80386CPU中的控制寄存器
or eax,1 ;第0位,即PE位,用来控制是否进入保护模式(是/否:1/0)
mov cr0,eax ;

jmp dword SelectorCode32:0 ;选择子是16位的,当然要用dword把它的属性定为32位的双字咯~

[SECTION .s32]
[BITS 32]

LABEL_SEG_CODE32:
mov ax,SelectorVideo ;将显示器的段地址传到GS寄存器
mov gs,ax ;

mov edi,(80*10+0)*2 ;显存的偏移地址edi,决定了在显示器上显示的位置
mov ah,0Ch ;
mov al,'P' ;
mov [gs:edi],ax ;而物理地址[gs:edi]中的内容,则决定了显示的内容,AH为显示属性,AL为显示内容

jmp $

SegCode32Len equ $ - LABEL_SEG_CODE32
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: