标签:
总算把进入保护模式的代码读懂了,照抄贴出来,讲是讲不明白了!!
; TestPM.nas ; 初识保护模式 ; 四彩 ; 2015-11-15 ; ======================================================================================== ; ---------------------------------------------------------------------------------------- ; 描述符说明(8 字节 64 位) ; ; ------ ┏━━┳━━┓内存高地址 ; ┃ 7 ┃ 段 ┃ ; ┣━━┫ 基 ┃ ; ┆ ┆ 址 ┆ ; 字节 ┆ ┆ 高 ┆ ; 7 ┣━━┫ 8 ┃ ; ┃ 0 ┃ 位 ┃ ; ------ ┣━━╋━━┫ ; ┃ 7 ┃ G ┃ ; ┣━━╉━━┨ ; ┃ 6 ┃D/B ┃ ; ┣━━╉━━┨ ; ┃ 5 ┃ 未 ┃ ; ┣━━┫ 定 ┃ ; ┃ 4 ┃ 义 ┃ ; 字节 ┣━━╉━━┨ ; 6 ┃ 3 ┃ ┃ ; ┣━━┫ 段 ┃ ; ┃ 2 ┃ 界 ┃ ; ┣━━┫ 限 ┃ ; ┃ 1 ┃ 高 ┃ ; ┣━━┫ 4 ┃ ; ┃ 0 ┃ 位 ┃ ; ------ ┣━━╋━━┫ ; ┃ 7 ┃ P ┃ ; ┣━━╉━━┨ ; ┃ 6 ┃ D ┃ ; ┣━━┫ P ┃ ; ┃ 5 ┃ L ┃ ; ┣━━╉━━┨ ; ┃ 4 ┃ S ┃ ; 字节 ┣━━╉━━┨ ; 5 ┃ 3 ┃ ┃ ; ┣━━┫ T ┃ ; ┃ 2 ┃ Y ┃ ; ┣━━┫ P ┃ ; ┃ 1 ┃ E ┃ ; ┣━━┫ ┃ ; ┃ 0 ┃ ┃ ; ------ ┣━━╋━━┫ ; ┃ 23 ┃ ┃ ; ┣━━┫ ┃ ; ┃ 22 ┃ 段 ┃ ; ┣━━┫ 基 ┃ ; ┆ ┆ 址 ┆ ; 字节 ┆ ┆ 低 ┆ ; 2,3,4 ┣━━┫ 24 ┃ ; ┃ 1 ┃ 位 ┃ ; ┣━━┫ ┃ ; ┃ 0 ┃ ┃ ; ------ ┣━━╋━━┫ ; ┃ 15 ┃ ┃ ; ┣━━┫ ┃ ; ┃ 14 ┃ 段 ┃ ; ┣━━┫ 界 ┃ ; ┆ ┆ 限 ┆ ; 字节 ┆ ┆ 低 ┆ ; 0,1 ┣━━┫ 16 ┃ ; ┃ 1 ┃ 位 ┃ ; ┣━━┫ ┃ ; ┃ 0 ┃ ┃ ; ------ ┗━━┻━━┛内存低地址 ; ; 描述符定义宏:(看不明白的话,把 16 进制换成 2 进制就很清楚了) ; 调用格式:Descriptor Base, Limit, Attribute ; Base : dd ; 基址,32 位 ; Limit : dd ; 界限,32 位,低 20 位有效 ; Attribute : dw ; 属性,16 位,高 4 位和低 8 位有效,中间 4 位无效。 %macro Descriptor 3 dw %2 & 0xFFFF ; 界限低 16 位 dw %1 & 0xFFFF ; 基址低 16 位 db (%1 >> 16) & 0xFF ; 基址中间 8 位(高字节的低字) dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性低 8 位 + 界限高 4 位 + 属性高 4 位 = ; %2 的高字的低字节的低 4 位替换 %3 高字中的低 4 位 db (%1 >> 24) & 0xFF ; 基址高 8 位 %endmacro ; 共占用 8 个字节(64 位) ; ; ---------------------------------------------------------------------------------------- ; 描述符属性: ; 描述符属性是一个字型数值,但是只有高 4 位和低 8 位有效,中间 4 位无效。 ; ┏━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┓ ; ┃15┃14┃13┃12┃11┃10┃09┃08┃07┃06┃05┃04┃03┃02┃01┃0 ┃ ; ┣━┻━┻━┻━╋━┻━┻━┻━╋━╋━┻━╋━╋━┻━┻━┻━┫ ; ┃G ┃DB┃R ┃A ┃ 无效位 ┃P ┃ DPL ┃S ┃ TYPE ┃ ; ┗━┻━┻━┻━┻━━━━━━━┻━┻━━━┻━┻━━━━━━━┛ ; 11、G:Granularity,界限粒度位 ; G = 0 界限粒度为 1 字节; ; G = 1 界限粒度为 4K 字节。 ; 注意,界限粒度只对段界限有效,对段基地址无效,段基地址总是以字节为单位。 ; ; 10、DB:Default operation size / default stack pointer size and/or upper bound ; 默认操作大小/默认栈指针大小和/或上界限位,根据描述的段不同,功能不同。 ; 对于 32 位代码和数据段,应该总是设置为 1;对于 16 位代码和数据段,应该总是设置为 0。 ; ⑴ 可执行代码段(D):指明指令引用有效地址和操作数的默认长度。 ; ① D = 1 默认为 32 位代码段,指令使用 32 位地址及 32 或 8 位操作数; ; ② D = 0 默认为 16 位代码段,指令使用 16 位地址及 16 或 8 位操作数。 ; 可以使用指令前缀 0x66 来选择非默认值的操作数大小、0x67 来选择非默认值的地址大小。 ; ⑵由 SS 寄存器指向的数据段,通常为堆栈段(B):指明堆栈操作指令默认栈指针大小。 ; ① D = 1 使用 32 位堆栈指针寄存器 ESP; ; ② D = 0 使用 16 位堆栈指针寄存器 SP。 ; ⑶ 向下扩展数据段(B):指明段的上界限。 ; ① D = 1 段的上界限为 4G; ; ② D = 0 段的上界限为 64K。 ; ; 09、R:Reserved,保留位 ; 未定义,应该总是设置为 0。 ; ; 08、A:Available,可用位 ; 未定义,可供系统软件使用。 ; ; 07、P:Present,段存在位 ; P = 1 该段在内存中,即该段存在,或者说描述符对地址转换是有效的; ; P = 0 该段不在内存中,即该段不存在,或者说描述符对地址转换无效。 ; 把指向这个段描述符的选择符加载进段寄存器将导致产生一个段不存在异常。 ; 内存管理软件可以使用这个标志来控制在某一给定时间实际需要把那个段加载进内存中。 ; 这个功能为虚拟存储提供了除分页机制以外的控制。 ; 操作系统可以使用该描述符来保存其他数据,如不存在段实际在什么地方。 ; ; 06 05、DPL:Descriptor Privilege level,特权级位 ; 规定了所描述段的特权级,用于特权检查,以决定对该段能否访问。 ; 特权级范围从 0 到 3,0 级特权级最高,3 级最低。 ; ; 04、S:Descriptor type flag,描述符类型位 ; S = 1 存储段 ; S = 0 系统段和门 ; ; 03 02 01 00、TYPE:说明存储段描述符所描述的存储段的具体属性。 ; 值 说明 ; ------------------------------------------ ; 系 0 未定义 ; 1 可用 286TSS ; 2 局部描述符表 ; 3 忙的 286TSS ; 4 286 调用门 ; 5 任务门 ; 6 286 中断门 ; 统 7 286 陷阱门 ; 8 未定义 ; 9 可用 386TSS ; A 未定义 ; B 忙的 386TSS ; C 386 调用门 ; D 未定义 ; E 386 中断门 ; 段 F 386 陷阱门 ; ------------------------------------------ ; 数 0 只读 ; 1 只读、已访问 ; 2 读/写 ; 据 3 读/写、已访问 ; 4 只读、向下扩展 ; 5 只读、向下扩展、已访问 ; 6 读/写、向下扩展 ; 段 7 读/写、向下扩展、已访问 ; ------------------------------------------ ; 代 8 只执行 ; 9 只执行、已访问 ; A 执行/读 ; 码 B 执行/读、已访问 ; C 只执行、一致码段 ; D 只执行、一致码段、已访问 ; E 执行/读、一致码段 ; 段 F 执行/读、一致码段、已访问 ; ; ---------------------------------------------------------------------------------------- ; 描述符属性常量定义: ; G 位,默认 1 字节粒度 DA_4k equ 0x8000 ; 4K 字节粒度,0b 1 000 0000 0000 0000 ; ; DB 位,默认 16 位 DA_32 equ 0x4000 ; 32 位,0b 1 00 0000 0000 0000 ; ; DPL 位,默认特权级 0 DA_DPL_1 equ 0x20 ; DPL = 1,0b 01 0 0000 DA_DPL_2 equ 0x40 ; DPL = 2,0b 10 0 0000 DA_DPL_3 equ 0x60 ; DPL = 3,0b 11 0 0000 ; ; P + S + TYPE 位 ; 都存在,代码段都可执行 ; P 存在:0x80,0b 1 000 0000, ; S 存储段:0x10,0b 1 0000 ; 系统段 DA_SS_LDT equ 0x82 ; 局部描述符表 DA_SS_TG equ 0x85 ; 任务门 DA_SS_386TSS equ 0x89 ; 可用 386 TSS(任务状态)段 DA_SS_386CG equ 0x8C ; 386 调用门 DA_SS_386IG equ 0x8E ; 386 中断门 DA_SS_386TG equ 0x8F ; 386 陷阱门 ; 数据段 DA_DS_R equ 0x90 ; 只读数据段 DA_DS_RW equ 0x92 ; 可读写数据段 DA_DS_RWA equ 0x93 ; 可读写、已访问数据段 ; 代码段 DA_CS equ 0x98 ; 代码段 DA_CS_R equ 0x9A ; 可读代码段 DA_CS_C equ 0x9C ; 一致代码段 DA_CS_RC equ 0x9E ; 可读、一致代码段 ; ; **************************************************************************************** ; ======================================================================================== ; 选择子: ; ---------------------------------------------------------------------------------------- ; ┏━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┳━┓ ; ┃15┃14┃13┃12┃11┃10┃09┃08┃07┃06┃05┃04┃03┃02┃01┃0 ┃ ; ┣━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━┻━╋━╋━┻━┫ ; ┃ 描述符索引 ┃TI┃ RPL ┃ ; ┗━━━━━━━━━━━━━━━━━━━━━━━━━┻━┻━━━┛ ; TI:Table Indicator,引用描述符表位 ; TI = 0 从全局描述符表(GDT)中读取描述符; ; TI = 1 从局部描述符表(LDT)中读取描述符。 ; RPL:Requested Privilege Level,请求特权级位 ; 用于特权检查。 ; ; ---------------------------------------------------------------------------------------- ; 选择子属性常量定义: ; TI 位,默认为全局描述符表 SA_LDT equ 4 ; 局部描述符表 ; ; RPL 位,默认请求特权级 0 SA_RPL_1 equ 1 SA_RPL_2 equ 2 SA_RPL_3 equ 3 ; ; **************************************************************************************** ; ======================================================================================== ; ---------------------------------------------------------------------------------------- org 0x7C00 jmp Label_RM_main ; **************************************************************************************** ; ======================================================================================== ; ---------------------------------------------------------------------------------------- ; GDT 段基址 段界限 属性 Label_Desc_Empty : Descriptor 0, 0, 0 ; 空描述符 Label_Desc_PM : Descriptor 0, 0xFFFF, DA_32 + DA_CS ; 保护模式代码段描述符 Label_Desc_Video : Descriptor 0xB8000, 0xFFFF, DA_DS_RW ; 显存段描述符 ; ---------------------------------------------------------------------------------------- ; GDTPtr GDTLen equ $ - Label_Desc_Empty GDTPtr dw GDTLen - 1 ; 界限 dd 0 ; 基址 ; ---------------------------------------------------------------------------------------- ; 选择子 SelectorPM equ Label_Desc_PM - Label_Desc_Empty SelectorVideo equ Label_Desc_Video - Label_Desc_Empty ; **************************************************************************************** [BITS 16] ; ======================================================================================== ; 实模式下开启保护模式 ; ---------------------------------------------------------------------------------------- ; 程序入口,实模式代码段 Label_RM_main: ; 填上保护模式代码段描述符的基址(界限、属性在定义时已初始化) xor eax, eax mov ax, cs shl eax, 4 add eax, Label_PM_main ; 保护模式程序入口的绝对内存地址,即为其基址 mov word[Label_Desc_PM + 2], ax ; 拆分成 3 部分存入相应位置 shr eax, 16 mov byte[Label_Desc_PM + 4], al mov byte[Label_Desc_PM + 7], ah ; 填上 GDTPtr 的基址(界限在定义时已初始化) xor eax, eax mov ax, cs shl eax, 4 add eax, Label_Desc_Empty mov dword[GDTPtr + 2], eax ; 加载 GDT lgdt [GDTPtr] ; 屏蔽中断 cli ; 打开地址线 A20 in al, 0x92 or al, 0b10 out 0x92, al ; 切换到保护模式 mov eax, cr0 or eax, 1 mov cr0, eax ; 修改 CS : EIP jmp dword SelectorPM : 0 ; **************************************************************************************** [BITS 32] ; ======================================================================================== ; 保护模式代码段,由实模式跳入 Label_PM_main: mov ax, SelectorVideo mov gs, ax mov edi, (80 * 5 + 35) * 2 mov ah, 0xC mov al, ‘O‘ mov [gs : edi], ax mov al, ‘K‘ mov [gs : edi + 2], ax jmp $ ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系统引导扇区引导代码的剩余部分用 0 填满 times 510 - ($ - $$) db 0 ; **************************************************************************************** ; ======================================================================================== ; FAT12 文件系统引导扇区的的结束标志(最后 2 字节,必须是 0xAA55) dw 0xAA55 ; **************************************************************************************** ; ======================================================================================== CodeLenOfPM equ $ - Label_PM_main ; ****************************************************************************************
运行下,成功!
标签:
原文地址:http://my.oschina.net/u/580100/blog/530488