美文网首页
[020][x86汇编语言]第11章 进入保护模式

[020][x86汇编语言]第11章 进入保护模式

作者: AkuRinbu | 来源:发表于2018-05-28 17:40 被阅读0次

    学习笔记

    《x86汇编语言:从实模式到保护模式》
    https://www.jianshu.com/p/d481cb547e9f

    代码参考

    • 配书代码 c11_mbr.asm

    运行结果

    第11章 程序运行结果.png

    参考图例

    图11-3 进入保护模式前的内存映象.png

    《x86汇编语言:从实模式到保护模式》 第187页

    完整源码(增加注释)

    ;代码清单11-1
    ;文件名:code_11.asm
    ;文件说明:  硬盘主引导扇区代码
    ;创建日期:  16:52 2018/5/29
    
    ;设置堆栈段和栈指针
    mov ax,cs
    mov ss,ax
    mov sp,0x7c00
    
    ;计算GDT所在的逻辑段地址
    mov ax,[cs:gdt_base+0x7c00]         ;低16位
    mov dx,[cs:gdt_base+0x7c00+0x02]    ;高16位
    mov bx,16
    div bx
    mov ds,ax                           ;令DS指向该段以进行操作
    mov bx,dx                           ;段内起始偏移地址0x0000
    
    ;创建0#描述符,它是空描述符,这是处理器的要求
    mov dword [bx+0x00],0x00
    mov dword [bx+0x04],0x00
    
    ;创建1#描述符,保护模式下的代码段描述符
    ;   段基地址0x00007C00
    ;   段界限0x001ff (段的长度=段界限+1=0x0200=512kb)
    ;   G=0 粒度为字节
    ;   S=1 这是代码段
    ;   D=1 这是32位段
    ;   DPL=00 段的特权级是0
    ;   P=1 该段目前在内存中
    ;   TYPE=1000 只执行
    mov dword [bx+0x08],0x7c0001ff
    mov dword [bx+0x0c],0x00409800
    
    ;创建2#描述符,保护模式下的数据段描述符(文本模式下的显示缓冲区)
    ;   段基地址0x000b8000
    ;   段界限0x0ffff
    ;   G=0 粒度为字节
    ;   S=1 这是数据段
    ;   D=1 这是32位段
    ;   DPL=00 段的特权级是0
    ;   P=1 该段目前在内存中
    ;   TYPE=0010 这是一个可读可写,向上扩展的数据段
    mov dword [bx+0x10],0x8000ffff
    mov dword [bx+0x14],0x0040920b
    
    ;创建3#描述符,保护模式下的堆栈段描述符
    ;段基地址0x00000000
    ;段界限07a00
    ;G=0 粒度为字节
    ;S=1 栈段
    ;D=1 这是32位段
    ;DPL=00 段的特权级是0
    ;P=1 该段目前在内存中
    ;TYPE=0110  这是一个可读可写、向下扩展的栈段
    mov dword [bx+0x18],0x00007a00
    mov dword [bx+0x1C],0x00409600
    
    
    ;初始化描述符表寄存器GDTR
    ;4*8-1=31 
    ;4个描述符:空白段描述符、代码段描述符、数据段描述符、栈段描述符
    ;每个描述符占8个字节
    mov word [cs:gdt_size+0x7c00],31 ;描述符表的界限(总字节数减一)
    lgdt [cs:gdt_size+0x7c00]
    
    
    in al,0x92              ;南桥芯片内的端口
    or al,0000_0010B
    out 0x92,al             ;打开A20:第21根地址线
    
    cli                     ;保护模式下中断机制尚未建立,应该禁止中断
    
    mov eax,cr0
    or eax,1
    mov cr0,eax             ;设置PE位,置为1,进入保护模式
    
    ;以下进入保护模式... ...
    jmp dword 0x0008:flush  ;16位的描述符选择子 : 32位偏移
                            ;dword修饰的是偏移地址
                            ;清空流水线
                            ;串行化处理器,让指令重新按自然顺序执行
    [bits 32]               
    
    flush:
        mov cx,00000000000_10_000B  ;加载选择子(0x10)
        mov ds,cx
        
        ;以下在屏幕上显示“Protect mode OK."
        mov byte [0x00],'P'
        mov byte [0x02],'r'
        mov byte [0x04],'o'
        mov byte [0x06],'t'
        mov byte [0x08],'e'
        mov byte [0x0a],'c'
        mov byte [0x0c],'t'
        mov byte [0x0e],' '
        mov byte [0x10],'m'
        mov byte [0x12],'o'
        mov byte [0x14],'d'
        mov byte [0x16],'e'
        mov byte [0x18],' '
        mov byte [0x1a],'O'
        mov byte [0x1c],'K'
        mov byte [0x1e],'.'
        
        
        ghalt:
            hlt             ;已经禁止中断,将不会被唤醒
    ;-------------------------------------------------------
        gdt_size    dw  0
        gdt_base    dd  0x00007e00      ;GDT的物理地址
        
        times 510-($-$$)    db  0
                            db 0x55,0xaa
    

    代码说明

    加载段选择子0x0008 索引号是1.png
    • jmp dword 0x0008:flush ,这条指令,用bits16编译,在16位模式下译码,按照32位执行;
    段选择子0x0008
    展开成二进制是
    0000-0000-0000-1000
    再按照段选择子的格式来分
    0000-0000-00001-0-00
    这一部分 0000-0000-00001 就是索引号
    这样就是用13位来表示索引号
    
    为什么是13位?
    因为GDT最大是64kb
    64kb=2^16Byte
    单个描述符占用8个字节,也就是占用2^3个字节
    (2^16)/(2^3)=2^13 即索引号个数。
    
    • 处理器遇到 jmp或者call 指令,一般会清空流水线,并串行化执行(让指令重新按照自然顺序执行);
    • ESP寄存器要满足ESP>段界限*粒度

    相关文章

      网友评论

          本文标题:[020][x86汇编语言]第11章 进入保护模式

          本文链接:https://www.haomeiwen.com/subject/keyajftx.html