3-1代码

来源:互联网 发布:联通e卡是什么网络 编辑:程序博客网 时间:2024/05/17 15:58

     由于第二章没有代码,今天看了第三章的第一个代码,把自己理解的写出来,就当笔记吧,如果能帮助大家,不胜荣幸。

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


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


org 0100h
jmp LABEL_BEGIN


 ;---------------------------------------------------------全局描述表定义和选择子定义--------------------------------------------------------------------------
 ;------------------------------------------------------------------------------------------------------------------------------------------
[SECTION .gdt]
; GDT
;                                         段基址,      段界限     , 属性
LABEL_GDT: Descriptor      0,                0, 0     ; 空描述符
LABEL_DESC_CODE32: Descriptor      0, SegCode32Len - 1, DA_C + DA_32 ; 非一致代码段, 32


;程序设置了一个段描述符用于访问屏幕缓冲区,屏幕缓冲区位于内存000B8000H处,屏幕上的每个字符在缓冲区占2个字节,第1个字节存放字符的ASCII码,第2个字节存放字符的属性(前景颜色、背景颜色)。
;屏幕一共有25行、每一行80个字符,位置(x,y)所对应的缓冲区地址为:
;000B8000h + (y * 80 + x) * 2                   (x=0-24, y=0-79)
;描述符中,基地址设为000B8000h,将其选择符DataV_Sel赋给GS。GS:[(y * 80 + x) * 2]对应于位置(x,y)所在的字符,GS:[(y * 80 + x) * 2 + 1]对应于该字符的显示属性。


LABEL_DESC_VIDEO: Descriptor0B8000h,           0ffffh, DA_DRW ; 显存首地址   DA_DRW的意思是:存在的可读写数据段属性值
; GDT 结束


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


; GDT 选择子
SelectorCode32 equLABEL_DESC_CODE32 - LABEL_GDT    ;代码段选择子
SelectorVideo equLABEL_DESC_VIDEO - LABEL_GDT   ;视频段选择子
; END of [SECTION .gdt]
;----------------------------------------------------------------------------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------------------------------------------




[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
      ;初始化ds和es两个寄存器,和确定堆栈
mov ax, cs                              ;使ds和es两个寄存器指向与cs相同的段,以便在今后进行数据操作的时候能够正确定位
mov ds, ax                              ;CS是代码段
mov es, ax
mov ss, ax
mov sp, 0100h    ;sp 堆栈指针


      ;----------实模式下的寻址的方式固然还是段:偏移,而且段:偏移还都是16位,但在实模式下却可以使用32位寄存器----------------------

      ; 初始化 32 位代码段描述符
xor eax, eax                   ;将eax指令清0
mov ax, cs              ;
shl eax, 4                   ;逻辑左移指令 ,留下的空白用0补  (这是段地址*16)
add eax, LABEL_SEG_CODE32     ;有效地址=段地址*16+offset
mov word [LABEL_DESC_CODE32 + 2], ax     ;用eax分成三部分 赋给描述符DESC_CODE32中的相应位置
shr eax, 16                             ;右移16位,使高位的16位变到低位16为,便于操作,赋值
mov byte [LABEL_DESC_CODE32 + 4], al    ;表述符的第四位
mov byte [LABEL_DESC_CODE32 + 7], ah   ;描述符的第7位


; 为加载 GDTR 作准备
xor eax, eax         ;将eax清零
mov ax, ds         ;将16位的段值DS复制给AX
shl eax, 4          ;用eax表示数据段的物理地址,左移是表示段那部分
add eax, LABEL_GDT ;自己理解:LABEL_GDT是相对于段的地址,即成为偏移地址
mov dword [GdtPtr + 2], eax; 把gdt即全局描述表的物理地址加载到 GdtPtr


; 加载 GDTR
lgdt [GdtPtr]   ; 通过lgdt汇编指令可以把GDTR描述符表的大小和起始位置存入gdtr寄存器中,指令格式如下:
                                       ;[描述段描述符表的地址]       这样以后能方便寻找




; 关中断
cli


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


; 准备切换到保护模式
mov eax, cr0       ;cro 是32位的寄存器
or eax, 1
mov cr0, eax      ;将cro的0位置置1,因为cro寄存器的0位决定是 实模式还是保护模式


; 真正进入保护模式
jmp dword SelectorCode32:0; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处

;SelectorCode32是保护模式代码的选择子,dword 修饰offset偏移地址,因为偏移地址应该是32位的,JMP指令,将选择子加载入ecs,代码进入保护模式执行
;SelectorCode32是代码段的选择子。
      ;CPU使用这个选择子去GDT中查找段描述符。找到这个描述符之后,再从中取出段基址。冒号后头的是段内偏移。计算的方法仍然是段基址+段内偏移。
      ;只是段基址不再是直接给出的了,要通过GDT绕一个弯子。
; END of [SECTION .s16]




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


LABEL_SEG_CODE32:
; 屏幕第 10 行, 第 0 列。
mov ah, 0Ch; 0000: 黑底    1100: 红字
mov al, 'P'
mov [gs:edi], ax


; 到此停止
jmp $


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

原创粉丝点击