日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

【操作系统】模式切换篇

發(fā)布時(shí)間:2024/1/18 windows 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【操作系统】模式切换篇 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

CPU的模式

什么是CPU的模式?這和CPU的發(fā)展過程有關(guān),最開始CPU是8位的,后來發(fā)展到16位,然后是32位,現(xiàn)在是64位,多少多少位指的是寄存器的位寬。CPU能使用的寄存器寬度以及CPU使用的指令等就構(gòu)成了CPU的模式,比如16位模式和32位模式,注意除了寄存器,不同模式下CPU對指令的解釋也是不同的,因此16位模式的程序是不能在32位模式下運(yùn)行的。為了向后兼容,后來的CPU要能運(yùn)行在之前CPU的模式下,比如32位CPU也能跑16位模式,這樣在之前CPU上編寫的程序也能在新CPU上運(yùn)行。

說到CPU的模式,我們常常會(huì)看到16位實(shí)模式,32位保護(hù)模式這樣的概念,單從字面上看,讓人像個(gè)丈二的和尚。這兩個(gè)概念其實(shí)包含了兩對概念:

  • 16位和32位
  • 實(shí)模式和保護(hù)模式

16位和32位模式很好理解,它描述的是寄存器的寬度和CPU的指令。實(shí)模式和保護(hù)模式是個(gè)啥呢?要理解這兩個(gè)概念,我們需要看下這兩個(gè)概念的英文原文。

  • 實(shí)模式原文是real address mode(簡稱為real mode),全稱真實(shí)地址模式。
  • 保護(hù)模式原文是protected virtual address mode,全稱受保護(hù)的虛擬地址模式。

首先我們可以看到它們限定的實(shí)體都是尋址模式(address mode),也就是CPU訪問內(nèi)存的方式。CPU訪問內(nèi)存不都是二維數(shù)組的形式嗎?為何還有虛實(shí)之分呢?

這里的虛和實(shí)指的是段寄存器中的值是(真實(shí)的)二維數(shù)組下標(biāo),還是(虛假的)段描述符偏移。由于虛擬尋址模式下可以控制內(nèi)存是否允許被訪問,所以它又多了一個(gè)限定:受保護(hù)的。這也意味著在真實(shí)尋址模式下,對任意內(nèi)存的訪問都是始終被允許的,是不具備段保護(hù)功能的。

保護(hù)模式下的段尋址

在切換到保護(hù)模式之前,我們還得再嘮嘮段尋址,上次嘮了5毛錢的,這次再嘮5毛錢。

首先來回顧一下段尋址的本質(zhì),所謂段尋址就是把一維數(shù)組抽象成二維數(shù)組,用二維數(shù)組下標(biāo)來定位內(nèi)存字節(jié),CPU會(huì)幫我們把二維下標(biāo)換算成一維下標(biāo),這一點(diǎn)依然沒有改變。

實(shí)地址模式下段寄存器指哪打哪,CPU沒有拒絕的理由,然而在保護(hù)模式下,CPU是可以拒絕非法的段尋址的,因此,保護(hù)模式保護(hù)的是段,而不是某個(gè)或某幾個(gè)任意的內(nèi)存字節(jié)。在保護(hù)模式下,CPU除了需要知道段的起始地址,還需要知道關(guān)于這個(gè)段的一些屬性,比如段的類型,安全級(jí)別等等。這么多的信息,段寄存器肯定是放不下了,要知道即使是在32位(包括64位)模式下,段寄存器依然只有16位。

為了解決這個(gè)問題,我們需要把段的相關(guān)信息放到內(nèi)存中,相比于寄存器,內(nèi)存就如同大海一樣。這些放在內(nèi)存中的段信息稱為全局描述符表,英文名Global Descriptor Table,簡稱GDT。全局描述符表中的每一項(xiàng)代表了一個(gè)段的信息,稱為段描述符,英文叫Segment Descriptor,簡稱SD。與此同時(shí),我們還要告訴CPU全局描述符表的起始地址和長度,這樣CPU才知道GDT放在那里,這里GDT的起始地址和長度叫做GDT描述符。之后我們使用段尋址時(shí),給到段寄存器的其實(shí)是SD相對于GDT起始地址的偏移量。32位保護(hù)模式下SD的大小為8字節(jié),如果我們將段寄存器設(shè)置為0x8,那么CPU就會(huì)使用GDT中的第二個(gè)段描述符,如下圖所示。注意GDT的第一個(gè)段描述符是null,也就是全零,設(shè)置這樣一個(gè)非法的段描述符是為了防止從16位實(shí)地址模式切換到32位保護(hù)模式后忘記設(shè)置段寄存器引發(fā)的問題。

段描述符中主要包括段的起始地址,段的大小和段的屬性3大部分,SD的結(jié)構(gòu)如下圖所示。

段大小和段起始地址在這8個(gè)字節(jié)中并不是連續(xù)分布的,這樣的設(shè)計(jì)我也想不通,像極了一開始沒有預(yù)留足夠的空間,后來又加上的。

注意Type字段有4個(gè)字節(jié),X用來區(qū)分代碼段還是數(shù)據(jù)段,中間兩個(gè)比特在代碼段和數(shù)段中的解釋是不同的,在代碼段中,C=0表示該段的代碼不能被特權(quán)等級(jí)(DPL)比它低的段中的代碼調(diào)用,也就是說只有特權(quán)等級(jí)更高或相同的段才能調(diào)用這個(gè)段中的代碼,這就是保護(hù)模式的關(guān)鍵所在。

切換到32位保護(hù)模式:啟動(dòng)超級(jí)變換形態(tài)

我們不能總是讓CPU在16位實(shí)地址模式下工作,在真正執(zhí)行操作系統(tǒng)之前,我們必須將CPU切換到32位保護(hù)模式,一是因?yàn)樾矢?#xff0c;我們可以利用32位寄存器,二是因?yàn)?2位保護(hù)模式下段尋址方式發(fā)生了變化,CPU可以拒絕非法的地址訪問。

進(jìn)入32位保護(hù)模式同時(shí)也意味著我們要離開BIOS了,因?yàn)锽IOS是為16位指令編譯的,沒法在32位模式下使用。因此一旦切換到32位保護(hù)模式,包括驅(qū)動(dòng)屏幕,鍵盤,硬盤等都需要我們自己來編寫程序?qū)崿F(xiàn)了,這絕對是大顯身手的好機(jī)會(huì),不管怎樣,我們先切換過去再說。

切換到保護(hù)模式需要在內(nèi)存中準(zhǔn)備兩個(gè)東西,一個(gè)是GDT,一個(gè)是GDT描述符。CPU提供了lgdt指令來設(shè)置全局段描述符,這只是準(zhǔn)備工作,真正讓CPU進(jìn)入32位模式還需要將cr0寄存器的最后一位設(shè)置位1。注意,最然我們一直在說32位保護(hù)模式,但是它其實(shí)包含了兩個(gè)概念,32位模式和保護(hù)模式,要分別進(jìn)行設(shè)置。

注意我們還沒介紹中斷向量表(IDT),所以目前我們要關(guān)閉中斷,因?yàn)?2位模式下BIOS提供的那些中斷也不能用了,因?yàn)锽IOS的程序都是16位指令,無法在32位模式下運(yùn)行。所以,我們還是先關(guān)閉中斷吧。

;; 準(zhǔn)備GDT gdt_start: gdt_null:dd 0, 0 ; 第一個(gè)段描述符必須是null gdt_code:dw 0xffff ; Limit(0-15位)dw 0x0 ; 基址(0-15位)db 0x0 ; 基址(16-23位)db 10011010b ; 第一個(gè)標(biāo)志+類型標(biāo)志db 11001111b ; 第二個(gè)標(biāo)志+Limit(16-19位)db 0x0 ; 基址(24-31位) gdt_data:dw 0xffff ; Limit(0-15位)dw 0x0 ; 基址(0-15位)db 0x0 ; 基址(16-23位)db 10010010b ; 第一個(gè)標(biāo)志+類型標(biāo)志db 11001111b ; 第二個(gè)標(biāo)志+Limit(16-19位) db 0x0 ; 基址(24-31位) gdt_end:;; GDT描述符 gdt_descriptor:dw gdt_end - gdt_start - 1 ; GDT大小,總是真實(shí)大小減一dd gdt_start ; GDT起始地址CODE_SEG equ gdt_code - gdt_start ; 代碼段描述符偏移量 DATA_SEG equ gdt_data - gdt_start ; 數(shù)據(jù)段描述符偏移量;; 切換保護(hù)模式 cli ; 關(guān)閉中斷,因?yàn)槲覀冞€沒有設(shè)置好保護(hù)模式下的中斷向量表 lgdt [gdt_descriptor] ; 設(shè)置GDT mov eax, cr0 or eax, 0x1 ; 將cr0寄存器的最后一位設(shè)置為1進(jìn)入32位模式 mov cr0, eax jmp CODE_SEG:init_pm ; 進(jìn)行一個(gè)遠(yuǎn)跳轉(zhuǎn)(機(jī)器碼EA),清空指令流水線,; 因?yàn)镃PU已經(jīng)處于32位模式了,指令流水線中的16位指令需要清空掉bits 32 ; 編譯為32位指令,也可寫作[bits 32] ;; 初始化保護(hù)模式 init_pm:mov ax, DATA_SEG ; 在保護(hù)模式,舊的段已經(jīng)沒有用了,mov ds, ax ; 所以,我們將段寄存器指向GDT中定義得數(shù)據(jù)段mov es, ax mov fs, ax mov gs, axmov ebp , 0x90000 ; 更新棧得位置mov esp , ebpjmp $ ; for {}

上面就是切換到32位保護(hù)模式的過程了,關(guān)于GDT的設(shè)置,目前我們只做了最簡單可行的配置,數(shù)據(jù)段和代碼段是重疊的,作為示例,先這樣吧。

進(jìn)入操作系統(tǒng)

我們已經(jīng)介紹了足夠多的基礎(chǔ)知識(shí)了,也知道了操作系統(tǒng)是如何啟動(dòng)的,我們已經(jīng)在引導(dǎo)扇區(qū)里和BIOS玩的夠久了,是時(shí)候真正進(jìn)入操作系統(tǒng)了。

;; 啟動(dòng)扇區(qū) org 0x7c00 ; 也可以寫作 [org 0x7c00]OS_ADDR equ 0x7e00 ; 操作系統(tǒng)內(nèi)存地址 VIDEO_ADDR equ 0xb8000 ; 幀緩存地址 CODE_SEG equ gdt_code - gdt_start ; 代碼段描述符偏移量 DATA_SEG equ gdt_data - gdt_start ; 數(shù)據(jù)段描述符偏移量;; =================== ;; 1.讀盤 ;; 2.準(zhǔn)備GDT ;; 3.切換32位保護(hù)模式 ;; 4.跳轉(zhuǎn)到操作系統(tǒng) ;; ===================mov [boot_device], dl ; 保存引導(dǎo)盤的驅(qū)動(dòng)器號(hào) ;; 讀盤 mov ah, 0x2 ; 讀磁盤 mov al, 0x10 ; 扇區(qū)數(shù),16×512B=8KB mov ch, 0 ; 柱面,從0開始 mov cl, 2 ; 扇區(qū),從1開始 mov dh, 0 ; 磁頭,從0開始 mov dl, [boot_device] ; 驅(qū)動(dòng)器號(hào),0:軟驅(qū)A,1:軟驅(qū)B,0x80:磁盤C mov bx, OS_ADDR ; 數(shù)據(jù)地址 int 0x13 ; 磁盤中斷 jc read_disk_err ; 讀盤失敗則跳轉(zhuǎn)到read_disk_err ;; 清屏 mov ah, 0x6 ; 屏幕初始化或上卷 mov al, 0x0 ; 上卷行數(shù),0表示整個(gè)窗口空白 mov bh, 0x0 ; 卷入后空出的行的寫入屬性 mov ch, 0x0 ; 左上角行號(hào) mov cl, 0x0 ; 左上角列號(hào) mov dh, 0x18 ; 右下角行號(hào) mov dl, 0x4f ; 右下角列號(hào) int 0x10 ; 觸發(fā)中斷 ;; 切換保護(hù)模式 cli ; 關(guān)閉中斷,因?yàn)槲覀冞€沒有設(shè)置好保護(hù)模式下的中斷向量表 lgdt [gdt_descriptor] ; 設(shè)置GDT mov eax, cr0 ; 將寄存器cr0的最 or eax, 0x1 ; 后一位設(shè)置為1后, mov cr0, eax ; CPU進(jìn)入32位模式 jmp CODE_SEG:init_pm ; 執(zhí)行一個(gè)遠(yuǎn)跳轉(zhuǎn)(機(jī)器碼EA),清空CPU指令流水線read_disk_err:mov si, err_code_read_disk ; 錯(cuò)誤碼寫入地址call hex2str ; 將錯(cuò)誤碼轉(zhuǎn)換成十六進(jìn)制字符串mov ah, 0x13 ; 顯示字符串mov al, 0x1 ; 寫入模式mov cx, 0x14 ; 字符串長度mov dh, 0x8 ; 顯示位置的行號(hào)mov dl, 0x0 ; 顯示位置的列號(hào)mov bp, err_read_disk ; 字符串地址mov bh, 0 ; 頁號(hào)mov bl, 0x4 ; 字符顯示屬性int 0x10 ; 打印字符串中斷jmp fin;; 函數(shù) hex2str:pushaadd si, 1shr ax, 4shr al, 4call hex2asciisub si, 1shr ax, 8call hex2asciipoparethex2ascii:pushaadd al, 0x30cmp al, 0x39jle .numadd al, 0x7.num:mov [si], alpoparetfin:hltjmp finbits 32 ; 編譯為32位指令 init_pm:mov ax, DATA_SEG ; 在保護(hù)模式,舊的段已經(jīng)沒有用了,mov ds, ax ; 所以,我們將段寄存器指向GDT中定義得數(shù)據(jù)段mov es, ax mov fs, ax mov gs, axmov ebp, 0x9fb00 ; 更新棧得位置,指向空閑空間的頂部mov esp, ebpcall OS_ADDR ; 跳轉(zhuǎn)系統(tǒng)內(nèi)核,也就是os_main.fin:hltjmp .fin ; for {};; 數(shù)據(jù) boot_device: db 0 err_read_disk: db 'read disk failed:' err_code_read_disk: db '??H', 0 msg_load_os: db 'loading os...', 0;; 準(zhǔn)備GDT gdt_start: gdt_null:dd 0, 0 ; 第一個(gè)段描述符必須為null gdt_code: ; 代碼段dw 0xffff ; Limit(0-15位)dw 0x0 ; 基址(0-15位)db 0x0 ; 基址(16-23位)db 10011010b ; 第一個(gè)標(biāo)志+類型標(biāo)志db 11001111b ; 第二個(gè)標(biāo)志+Limit(16-19位)db 0x0 ; 基址(24-31位) gdt_data: ; 數(shù)據(jù)段dw 0xffff ; Limit(0-15位)dw 0x0 ; 基址(0-15位)db 0x0 ; 基址(16-23位)db 10010010b ; 第一個(gè)標(biāo)志+類型標(biāo)志db 11001111b ; 第二個(gè)標(biāo)志+Limit(16-19位) db 0x0 ; 基址(24-31位) gdt_end:;; GDT描述符 gdt_descriptor:dw gdt_end - gdt_start - 1 ; GDT大小,總是真實(shí)大小減一dd gdt_start ; GDT起始地址;; 填充引導(dǎo)扇區(qū) db 510+$$-$ dup 0 ; 填充0直到510字節(jié),$$=0x7c00 dw 0xaa55 ; 啟動(dòng)扇區(qū)標(biāo)識(shí);; 系統(tǒng)內(nèi)核 ; bits 32 os_main:mov word [VIDEO_ADDR], 0xf<<8|'A'jmp $db 512+os_main-$ dup 0;; 填充剩余扇區(qū),因?yàn)榍懊嫖覀冏x了16個(gè)扇區(qū) db 15*512 dup 0

如果你在屏幕左上角看到了’A’,那就說明我們成功進(jìn)入到了操作系統(tǒng)了。啥,這也能成功?在這里我不得不再次提醒各位,內(nèi)存是一個(gè)數(shù)組,數(shù)組只有下標(biāo)和值。CPU只會(huì)傻傻的一條接著一條執(zhí)行指令,程序能否正確執(zhí)行,主要看能不能跳轉(zhuǎn)到正確的指令,能不能找到正確的數(shù)據(jù),而這其中的關(guān)鍵在于指令或數(shù)據(jù)的下標(biāo)是不是正確,下標(biāo),下標(biāo),它真的很重要。

大家一定要想明白call OS_ADDR是如何跳轉(zhuǎn)到os_main的,這里我們?nèi)×饲?#xff0c;代碼在磁盤鏡像中的布局和在內(nèi)存中的布局是一樣的,所以我們不需要使用org額外修正os_main的地址,是不是很神奇呢。

其實(shí)我們想做的事情非常簡單,將操作系統(tǒng)的機(jī)器指令讀到內(nèi)存中,放在一個(gè)指定的位置,然后在完成一些基本的初始化和設(shè)定后跳轉(zhuǎn)到操作系統(tǒng)的第一條指令所在的地址,至此操作系統(tǒng)登基稱帝,接管一切事物。雖然說起來不難,但是這條登基之路卻是充滿坎坷的。如果把寫操作系統(tǒng)比作登山,那現(xiàn)在我們還只是在山腳下轉(zhuǎn)了轉(zhuǎn),找到了一條上山的小路。

總結(jié)

以上是生活随笔為你收集整理的【操作系统】模式切换篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。