实模式切换到保护模式

代码是从于渊的书上抄过来的,不过书的注释简单得实在不行,加上汇编都差不多给回学校了,看了好几遍才把这些代码看透。看到虚拟机的屏幕上输出个”P”感觉不错 :) 。

从实模式到保护模式一般的过程为:

  • 建立起合适的全局描述符表。
  • 用lgdt加载GDTR,使GDTR指向GDT。
  • 打开A20地址线。PC及其兼容机的第20根地址线较特殊,计算机系统中一般安排一个“门”控制该地址线是否有效。为了访问地址在1M以上的存储单元,应先打开控制地址线A20的“门”。这种设置与实方式下只使用最的1M字节存储空间有关,与处理器是否工作在实方式和保护方式无关,即使在关闭地址线A20时,也可进行保护方式。
  • 置cr0的PE位。PE位为1表示运行在保护模式,为0表示运行在实方式。
  • 跳转,进入保护模式。

简单的切换代码如下(这个asm的着色是自己加上去的,着色得有点丑陋:)):

%macro Descriptor 3
    dw      %2 & 0FFFFh                                  ;; segment limit 1
    dw      %1 & 0FFFFh                                  ;; segment base 1
    db      (%1 >> 16) & 0FFh                            ;; segment base 2
    dw      ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)          ;; properties1 + segment limit 2 + properties2
    db      (%1 >> 24) & 0FFh                            ;; segment base 3
%endmacro

;; descriptor type
DA_32       equ     4000h   ;; 32 bits segment,D位设为1

;; descriptor type of data segment
DA_DRW      equ     92h     ;; accessed & readable
DA_C        equ     98h     ;; accessed & code segment

org     07c00h               ;;将这段程序加载到内存偏移地址0x7c00处 ,即引导代码的开始处
jmp     LABEL_BEGIN

[SECTION .gdt]
;; GDT 全局描述符表
                                    ;; base  limit   attr
LABEL_GDT:              Descriptor      0,      0,      0                           ;; void descriptor, gdt表第一个元素需为0
LABEL_DESC_CODE32:      Descriptor      0,      SegCode32Len - 1,     DA_C + DA_32  ;; unconforming code segment
LABEL_DESC_VIDEO:       Descriptor      0B8000h,    0FFFFh,     DA_DRW              ;; addr of video memory,文本显示模式下显储地址空间的段值是B800h
;; end GDT

GdtLen      equ     $ - LABEL_GDT   ;; GDT length
GdtPtr      dw      GdtLen - 1      ;; GDT limit
            dd      0               ;; GDT base addr

;; GDT selector,selector是一个索引
SelectorCode32      equ     LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo       equ     LABEL_DESC_VIDEO - LABEL_GDT

;; END of [SECTION .gdt]

[SECTION .s16]
[BITS   16]
LABEL_BEGIN:
        mov     ax,     cs
        mov     ds,     ax
        mov     es,     ax
        mov     ss,     ax
        mov     sp,     0100h

        ;; initialize descriptor of 32bits code segment
        xor     eax,    eax
        mov     ax,     cs
        shl     eax,    4
        add     eax,    LABEL_SEG_CODE32         ;;实模式下求得LABEL_SEG_CODE32的地址值
        mov     word [LABEL_DESC_CODE32 + 2],   ax    ;;将实模式下求得的LABEL_SEG_CODE32地址赋给LABEL_DESC_CODE32描述符
        shr     eax,    16
        mov     byte [LABEL_DESC_CODE32 + 4],   al
        mov     byte [LABEL_DESC_CODE32 + 7],   ah

        ;; prepare for loading gdtr
        xor     eax,    eax
        mov     ax,     ds
        shl     eax,    4
        add     eax,    LABEL_GDT       ;; eax < - gdt base addr
        mov     dword [GdtPtr + 2],     eax     ;; [GdtPtr + 2] <- gdt base addr

        ;; load GDTR
        lgdt    [GdtPtr]

        ;; close interupt
        cli

        ;; open addr bus A20
        in      al,     92h
        or      al,     00000010b
        out     92h,    al 

        ;; prepare for swithing to pmode,cr0的PE位设为1,表示在保护模式下运行
        mov     eax,    cr0
        or      eax,    1
        mov     cr0,    eax

        ;; jmp into pmode,32位的跳转
        jmp     dword SelectorCode32:0
;; END of [SECTION .s16]

[SECTION .s32]
[BITS   32]
LABEL_SEG_CODE32:
        mov     ax,     SelectorVideo
        mov     gs,     ax

        mov     edi,    (80 * 11 + 79) * 2          ;; row 11, col 79
        mov     ah,     0Ch
        mov     al,     'P'
        mov     [gs:edi],   ax

        ;; stop here
        jmp     $

SegCode32Len        equ     $ - LABEL_SEG_CODE32
;; END of [SECTION .s32]
This entry was posted in Operating System. Bookmark the permalink.

One Response to 实模式切换到保护模式

  1. runcoderen says:

    怎么没有解释啊

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>