注:属于个人学习分析及笔记,如有错误,请各位大牛指正 这部分比较简单,我就不仔细解释了 %include "pm.inc": org 07c00h ;告诉编译器,程序将加载到07c00h的位置 jmp LABEL_BEGIN ;转跳至LABEL_BEGIN处 [SECTION .gdt] ; 段基址, 段界限, 属性; LABEL_GDT Descriptor 0, 0, 0;空描述符 LABEL_DESC_CODE32 Descriptor 0, SegCode32Len - 1, DA_C + DA_32;代码描述符,段基址应为LABEL_SEG_CODE32 LABEL_DESC_VIDEO Descriptor 0B8000h, 0ffffh, DA_DRW;显存描述段,段基址应为显存首地址 GdtLen equ $ - LABEL_GDT;GDT长度 GdtPtr dw GdtLen - 1 ;GDT界限 dd 0 ;GDT基地址 SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT;3~15位也是其索引值,因为描述符的大小为8 SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT; [SECTION .s16] [BITS 16] LABEL_BEGIN: mov ax,cs mov ds,ax ;数据段 = 代码段 mov es,ax ;附加段 = 代码段 mov ss,ax ;堆栈段 = 代码段 mov sp,0100h ;抬高堆栈100字节 ;填充描述符表 xor eax,eax ;清0 eax寄存器 mov ax,cs shl eax,4 add eax,LABEL_SEG_CODE32 ;获得cs基地址,左移4位,再加上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 ;将LABEL_SEG_CODE32的物理地址填充回LABEL_DESC_CODE32 ;装载描诉符表 xor eax,eax ;清零EAX寄存器 mov ax ,ds shl eax,4 add eax,LABEL_GDT ;获得ds基地址,左移4位,再加上LABEL_GDT偏移地址,得到其物理地址 mov dword [GdtPtr + 2],eax ;填充回GdtPtr lgdt [GdtPtr] ;装载GdtPtr到GDTR cli ;关中断 in al,92h ;打开A20地址线 or al,00000010h out 92h,al mov eax,cr0 ;进入保护模式 or eax,1 mov cr0,eax jmp dword SelectorCode32:0 ;已为保护模式,转跳至保护模式代码 [SECTION .s32] [BITS 32] LABEL_SEG_CODE32: mov ax,SelectorVideo ;装载选择子 mov gs,ax mov edi,(80 * 11 + 79)*2 ;显示数据 mov ah,0ch mov al,'P' mov [gs:edi],ax jmp $ SegCode32Len equ $ - LABEL_SEG_CODE32