自己动手写操作系统第二章 pmtest1.asm分析

来源:互联网 发布:java 函数式编程 编辑:程序博客网 时间:2024/06/08 19:38

"pm.inc"

;描述符
;Usage:Descrptor Base,Limit,Attr
;   Base :dd
;      Limit:dd (Low 20 bits available)
;      Attr:dw (lower 4 bits of higher byte are always 0)


DA_C EQU 98h ; 存在的只执行代码段属性值
DA_DRW EQU 92h ; 存在的可读写数据段属性值
DA_32 EQU 4000h ; 32 位段


%macro Descriptor 3
dw %2 &0FFFFh ;段界限1
dw %1 & 0FFFFh  ;段基址1
db (%1 >> 16) & 0FFh;段基址2
dw ((%2 >> 8) & 0F00h) |(%3 & 0F0FFh)
;属性1+段界限2+属性2
db (%1 >> 24) & 0FFh;段基址3 
%endmacro ;共8字节


%include "pm.inc"
org 0100h
;ORG 0100h的实际含义
;PSP程序段前缀
;要了解ORG 0100h,就必须先了解程序段前缀PSP(Program Segment Prefix)
;程序段前缀是一个操作系统(DOS)概念。当输入一个外部命令或通过EXEC子功能
;(系统功能调用INT21h,子功能号为4Bh)加载一个程序时,COMMAND确定当前可用内存的最低端
;作为程序段的起点,也就是程序被加载到内存空间的起点。在程序所占用内存的前256(0100h)个
;字节中,DOS会为程序创建前缀(PSP)数据区。PSP结构与CP/M中的“控制区域”概念十分接近,
;这是因为DOS就是从CP/M演变而来的。
;DOS利用PSP与被加载的程序进行通信。PSP中有程序的返回地址、程序文件名等信息。
;16位DOS中,内存的物理地址=段地址*16 + 偏移量,比如段地址0xC0h,偏移量0x50h,
;则最后的物理地址是0xC0h * 16 + 0x50h = 0xC50h
;ORG用来告诉汇编器,程序加载到内存时的初始偏移量为0x100h,用于跳过PSP。
;比如你有一个标号Test的偏移地址是0x0Bh,当编译器看见ORG 0x100h后,就会给
;这个偏移加上0x100h,编译完成的.com文件中,这个偏移就变成了0x10Bh。
;如果你没有加ORG 0100h,则偏移仍然是0x0Bh,则访问该标号时,就跑到PSP里了,
;因为程序段的前0100h个字节,都是PSP的数据,而不是用户数据。
;同理,你写ORG 0x200h,则该标号的偏移地址在编译的.com文件中,会变成0x20Bh。
    jmp LABEL_BEGIN


[SECTION .gdt]
;GDT 定义了一个叫做GDT的数据结构
LABEL_GDT: Descriptor 0,0,0;空描述符
LABEL_DESC_CODE32: Descriptor 0,SegCode32Len-1,DA_C+DA_32;代码段,32位
LABEL_DESC_VIDEO: Descriptor 0B8000h,0ffffh,DA_DRW ;显存首地址
;GDT结束


GdtLen  equ $-LABEL_GDT ;GDT长度
GdtPtr  dw GdtLen ;GDT界限
        dd 0 ;GDT基地址 在16位代码段中被重新设置


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

;定义26位代码 进行与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

;mov ax,cs

;shl eax,4

;将cs的值(16bit 实模式下即为当前代码段的基地址) 

;左移4bit即得到当前代码段的物理基地址

;add eax,LABEL_SEF_CODE32

;此时eax即为实模式下LABEL_SEF_CODE32的物理地址

;然后再用此地址分为三部分去初始化LABEL_DESC_CODE32



;为加载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处

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

LABEL_SEG_CODE32:
   mov ax,SelectorVideo
mov gs,ax ;视频段选择子

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

;到此停止

jmp $
SegCode32Len equ $-LABEL_SEG_CODE32

;END of [SECTION .S32]































0 0
原创粉丝点击