作業系統實現之保護模式
保護模式主要是為了防止使用者程式故意使壞.而且使用者所引用的地址都是指向真實的實體地址.跟核心屬於同特權級.不利於安全.另外保護模式將是32/64位.大家所說的真實模式一般指的是32位的cpu在16位模式下的狀態.不是指的是16位cpu.本來沒有真實模式這個說法.不過後來出現保護模式.於是就出現了真實模式說法
保護模式下的改變
通用暫存器擴充套件為32位
段暫存器儲存的不再是段基址,而是段選擇子(段描述符的索引)
段基址儲存在段描述符中,而段描述符儲存在全域性描述符表(GDT)中. 而全域性描述符表儲存在專門的暫存器gdtr,載入時用lgdt指令進行載入
全域性描述符表(本簡單kernel沒用區域性描述符表)所儲存的描述符格式
之所以如此..混亂.完全是由於歷史相容原因
再來看看段選擇子(儲存在段暫存器中)的定義
保護模式下的選址方式發生了改變
一開始從段暫存器獲取段選擇子.通過段選擇子的索引位*8(乘以8是因為.一個段描述符是8個位元組)+gdtr儲存的全域性描述符表基址. 得到段基址
然後加上偏移暫存器.得到實際地址
如何進入保護模式:
1.開啟A20(歷史遺留問題.第21根地址線)
2.載入dgt
3.將cr0的pe位定義為1(表示進入保護模式)
-------------------------配置檔案boot.inc的定義----------------
-----------------mbr.S的定義(改動只有就是從扇區讀取4個扇區.而不是1個.因為loader.bin擴充了)----------------------------;------------- LOADER和KERNEL ---------- loader_base_addr equ 0X900 ;載入位置 loader_stack_top equ loader_base_addr ;棧指向的位置 loader_start_sector equ 0X2 ;loader儲存到第二個扇區 ;-------------- GDT描述符屬性 ----------- desc_g_4k equ 1_00000000000000000000000B ;描述符的g位為4k粒度 desc_d_32 equ 1_0000000000000000000000B ;表示是32位還是16位 desc_l equ 0_000000000000000000000B ; 64位程式碼標記,此處標記為0便可。 desc_avl equ 0_00000000000000000000B ; CPU不用此位,暫置為0 desc_limit_code2 equ 1111_0000000000000000B ;段的第二部分界限 desc_limit_data2 equ desc_limit_code2 desc_limit_video2 equ 0000_000000000000000B ; desc_p equ 1_000000000000000B desc_dpl_0 equ 00_0000000000000B ;段描述符特權級 desc_dpl_1 equ 01_0000000000000B desc_dpl_2 equ 10_0000000000000B desc_dpl_3 equ 11_0000000000000B desc_s_code equ 1_000000000000B desc_s_data equ desc_s_code desc_s_SYS equ 0_000000000000B desc_type_code equ 1000_00000000B ;X=1,C=0,R=0,A=0 程式碼段是可執行的,非依從的,不可讀的,已訪問位A清0. desc_type_data equ 0010_00000000B ;X=0,E=0,W=1,A=0 資料段是不可執行的,向上擴充套件的,可寫的,已訪問位A清0. ;段的24位 desc_code_high4 equ (0X00 << 24) + desc_g_4k + desc_d_32 + desc_l + desc_avl + desc_limit_code2 + desc_p + desc_dpl_0 + desc_s_code + desc_type_code + 0X00 desc_data_high4 equ (0X00 << 24) + desc_g_4k + desc_d_32 + desc_l + desc_avl + desc_limit_data2 + desc_p + desc_dpl_0 + desc_s_data + desc_type_data + 0X00 desc_video_high4 equ (0X00 << 24) + desc_g_4k + desc_d_32 + desc_l + desc_avl + desc_limit_video2 + desc_p + desc_dpl_0 + desc_s_data + desc_type_data + 0X0B ;-------------- 選擇子屬性 --------------- rpl0 equ 00B rpl1 equ 01B rpl2 equ 10B rpl3 equ 11B ti_gdt equ 000B ti_ldt equ 100B ;------------- PROGRAM TYPE 定義 -------------- pt_null equ 0
%include "boot.inc" ;儲存有關載入程式位置.源跟目的 section mbr vstart=0x7c00 jmp near start message db 'ZYW_OS start' start: ;ds:si指向資料來源.es:di指向視訊記憶體. mov sp,0x7c00 ;棧頂,棧成長的方向向上 mov ax,0xb800 mov es,ax ;es指向視訊記憶體位置 ; 清屏(摘自百度) ;利用0x06號功能,上卷全部行,則可清屏。 ; ----------------------------------------------------------- ;INT 0x10 功能號:0x06 功能描述:上卷視窗 ;------------------------------------------------------ ;輸入: ;AH 功能號= 0x06 ;AL = 上卷的行數(如果為0,表示全部) ;BH = 上卷行屬性 ;(CL,CH) = 視窗左上角的(X,Y)位置 ;(DL,DH) = 視窗右下角的(X,Y)位置 mov ax,0x0600 mov bx,0x0700 mov cx,0 ; 左上角: (0, 0) mov dx,0x184f ; 右下角(80,25), int 10h mov si,message mov di,0 mov cx,start-message zyw: movsb mov byte [es:di],0xA4 ;控制背景跟顏色 inc di loop zyw mov eax,loader_start_sector ;eax儲存載入程式的位置 mov bx,loader_base_addr ;bx儲存載入到哪個區域 mov cx,4 ;cx儲存載入幾個扇區(從eax開始) call read_disk jmp loader_base_addr read_disk: push eax mov dx,0x1f2 ;硬碟埠0x1f2 ,設定要讀取多少資料 mov al,cl ;這裡表示讀取一個 out dx,al pop eax ;將lba地址存入0x1f3-0x1f6處 mov dx,0x1f3 out dx,al push cx mov cl,8 shr eax,cl mov dx,0x1f4 out dx,al shr eax,cl mov dx,0x1f5 out dx,al shr eax,cl and al,0x0f or al,0xe0 mov dx,0x1f6 out dx,al pop cx ;向0x1f7寫入命令 mov dx,0x1f7 mov al,0x20 out dx,al noready: nop in al,dx and al,0x88 cmp al,0x08 jnz noready ;開始從0x1f0埠讀取資料 mov ax,cx mov dx,256 mul dx mov cx,ax mov dx,0x1f0 readdata: in ax,dx mov [bx],ax add bx,2 loop readdata ret times 510-($-$$) db 0 db 0x55,0xaa
-----------------loader的定義-------------------------------
%include "boot.inc"
section loader vstart=loader_base_addr
jmp start
;------------全域性描述符表的定義
gdt_base:
dd 0x00000000 ;全域性描述表.第一個描述符要為空
dd 0x00000000
code_base:
dd 0x0000FFFF
dd desc_code_high4
data_stack_desc:
dd 0x0000ffff
dd desc_data_high4
video_desc:
dd 0x80000007 ;段界限 limit=0x7fff.基址位於0xb8000
dd desc_video_high4
;---------GDT的屬性
gdt_size equ $-gdt_base ;GDT大小
gdt_limit equ gdt_size ;GDT限制
time 60 dq 0 ;預留60個描述符的空位置
;----------定義段選擇子-------------
selector_code equ (0x0001<<3)+ti_gdt+rpl0
selector_data equ (0x0002<<3)+ti_gdt+rpl0
selector_video eque(0x0003<<3)+ti_gdt+rpl0
;定義gdt的指標,前2個位元組為gdt界限,後4個位元組為gdt起始地址
gdt_ptr dw gdt_limit
dd gdt_base
;-----進入保護模式----------
in al,0x92
or al,0000_0010B
out 0x92,al
;----------載入GDT----------
lgdt [gdt_ptr]
;---------cr0第0位置為1,表示開啟保護模式-----------
mov eax,cr0
or eax,0x00000001
mov cr0,eax
jmp dword selector_code:p_mode_start:
[bits 32]
p_mode_start:
mov ax,selector_data
mov ds,ax
mov es,ax
mov ss,ax
mov esp,loader_stack_top
mov ax,selector_video
mov gs,ax
mov byte [gs:160],'P'
jmp $
顯示效果如圖<bochs:3> creg
CR0=0x60000011: pg CD NW ac wp ne ET ts em mp PE
從上可以看出 PE位已經置為1了
最後loader.S定義了
mov byte [gs:160],'P'
最終顯示效果.如果成功進入了保護模式.就會出現P這個字元