国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
X86 romInit.s分析

X86 CPU上電后,執(zhí)行的第一條指令位于何處?
同學(xué)們都知道,復(fù)位后CPU處于實(shí)模式,CS=0xF000,IP=0xFFF0,形成的線性地址為CS<<4+IP=0xFFFF0,也就是1M地址空間的最后16個(gè)字節(jié)的地方。由于尚未啟動(dòng)分頁(yè)機(jī)制,這個(gè)地址就是物理地址。很多書包括一些Linux的什么什么分析都是這樣說(shuō)的,然而這個(gè)結(jié)論對(duì)8086確實(shí)是對(duì)的,對(duì)于80286和386以上的CPU,情況要復(fù)雜一些。
對(duì)于386以上的處理器(386,486,Pentium),CS寄存器還存在一個(gè)48-bit的不可見(jiàn)部分,稱為代碼段高速緩存寄存器,它包含代碼段基地址(Base),段大?。↙imit),段屬性(Access)等,復(fù)位后的初始值如下所示:
EIP 0x0000FFF0
CS Selector = 0xF000
Base = 0xFFFF0000
Limit = 0xFFFF
AR = Present, R/W
Accessed
線性地址的計(jì)算方式是
線性地址 = Base + EIP
不管在實(shí)模式還是保護(hù)模式,都這樣計(jì)算。但在實(shí)模式下一旦修改CS的值,Base的值就會(huì)變?yōu)镃S*16(但初始值不滿足這個(gè)關(guān)系)。
由上面分析可知復(fù)位向量為0xFFFF0000+0x0000FFF0=0xFFFFFFF0,即4GB空間的最后16個(gè)字節(jié)的地方。在沒(méi)有啟動(dòng)分頁(yè)機(jī)制情況下,這就是CPU形成的物理地址。(有可能是通過(guò)主板硬件把它映射到0xF000:0xFFF0,總之PC主板制造者應(yīng)該會(huì)讓復(fù)位向量指向ROM BIOS。)
注:X86上有3種地址:段/偏移為邏輯地址,經(jīng)過(guò)分段處理(segmentation)變?yōu)榫€性地址;再經(jīng)過(guò)分頁(yè)(paging)變換為物理地址。一個(gè)段就是線性地址空間中的一塊,由于段之間可能會(huì)發(fā)生重疊,所以多個(gè)邏輯地址可能對(duì)應(yīng)同一個(gè)線性地址。
【A20地址線】
早 期的8086只有20根地址線,只能訪問(wèn)1M的地址空間。CPU尋址則按段+偏移的方式進(jìn)行。16位段+16位偏移的可能的范圍是 0~0x10FFEF(即0xFFFF0+0xFFFF),即1M+65520字節(jié)的范圍。由于只有20根地址線,所以在對(duì)1M~1M+65520范圍進(jìn)行訪問(wèn)時(shí),會(huì)發(fā)生“地址回繞”的現(xiàn)象,就是說(shuō)實(shí)際會(huì)訪問(wèn)到0~65520的地方。據(jù)說(shuō)某個(gè)著名的/臭名昭著的軟件利用了這個(gè)特點(diǎn)。在80286,386等 CPU上,它會(huì)失敗,因?yàn)檫@些CPU有多于20根的地址線,并不產(chǎn)生“地址回繞”現(xiàn)象。為了保持完全的兼容性,IBM決定在PC AT系統(tǒng)上加個(gè)邏輯,來(lái)模仿以上的回繞特征。他們的方法就是把A20和鍵盤控制器的一個(gè)輸出進(jìn)行AND,這樣來(lái)控制A20的打開(kāi)和關(guān)閉。一開(kāi)始時(shí)A20是被屏蔽的(總為0),直到系統(tǒng)軟件去打開(kāi)它。
注意A20而非A20~A31被控制,所以在A20關(guān)閉時(shí)會(huì)發(fā)生一些有趣的副作用。就是在訪問(wèn)奇數(shù)M地址空間的時(shí)候,實(shí)際的地址會(huì)減少1M。例如訪問(wèn)1M~2M-1時(shí)實(shí)際訪問(wèn)的是0~1M-1;訪問(wèn)3M~4M-1時(shí)為2M~3M-1,等等。
【BIOS】
PC上電后,BIOS從ROM中首先運(yùn)行。
BIOS啟動(dòng)后會(huì)進(jìn)行一系列的初始化操作,例如POST(Power-On Self-Test),初始化總線控制器和內(nèi)存控制器,檢測(cè)內(nèi)存,初始化PCI設(shè)備等等、等等。PC DIY者知道的要比我們多。
BIOS 初始化完成后把軟盤的第一個(gè)扇區(qū)(引導(dǎo)扇區(qū),512字節(jié))或者硬盤的第一個(gè)扇區(qū)(主引導(dǎo)扇區(qū)MBR,512字節(jié))讀到內(nèi)存的0x7C00處,然后跳轉(zhuǎn)到 0x7C00處執(zhí)行。這樣就將控制權(quán)轉(zhuǎn)移到了引導(dǎo)記錄。一般情況下,引導(dǎo)記錄是安裝操作系統(tǒng)時(shí)安裝的;也可能是其它的工具軟件,例如 LILO,SystemCommand等,可以有選擇地從多個(gè)操作系統(tǒng)的某一個(gè)啟動(dòng)。
MBR運(yùn)行后會(huì)搜索硬盤的可引導(dǎo)分區(qū)(活動(dòng)分區(qū)),加載該分區(qū)的引導(dǎo)扇區(qū)的內(nèi)容。引導(dǎo)扇區(qū)中的程序叫引導(dǎo)程序。
VxWorks 的引導(dǎo)程序叫VxLd,由Tornado工具vxsys.com寫入。它運(yùn)行后會(huì)從當(dāng)前磁盤的根目錄下加載BOOTROM.SYS(此文件必須連續(xù)存放,因?yàn)閂xLd很簡(jiǎn)單,還不認(rèn)識(shí)任何文件系統(tǒng)),加載地址為0x8000。這個(gè)步驟通過(guò)調(diào)用BIOS INT13完成。加載完成后跳轉(zhuǎn)到0x8000執(zhí)行。VxWorks操作系統(tǒng)的第一條指令就存放于0x8000的地方(注:這是bootrom;對(duì)于 vxWorks image為0x108000;或者相反)。
注意在PC目標(biāo)機(jī)上,VxWorks和BIOS的關(guān)系。VxWorks假定BIOS 已經(jīng)正確地初始化系統(tǒng)硬件,包括內(nèi)存,PCI總線等,所以pc386,pc486等BSP就省掉了很多工作。然而VxWorks啟動(dòng)后,不會(huì)用到BIOS 的任何功能,這和DOS不一樣。因?yàn)閂xWorks運(yùn)行于保護(hù)模式,而B(niǎo)IOS功能必須從實(shí)模式下調(diào)用(也許有人可以給我們說(shuō)說(shuō)如何在保護(hù)模式下如何調(diào)用 BIOS功能,當(dāng)然這是一個(gè)高級(jí)話題)。實(shí)際在一般正常情況下,當(dāng)VxWorks運(yùn)行后,BIOS就徹底消失了?!緍omInit.s的編譯過(guò)程】
編譯romInit.s時(shí)執(zhí)行的指令為:
cc386 -BD:\Tornado/host/x86-win32/lib/gcc-lib/ -mno-486 -ansi -nostdinc -O -fvolatile -nostdlib -fno-builtin -fno-defer-pop -I/h -I. -ID:\Tornado\target\config\all -ID:\Tornado\target/h -ID:\Tornado\target/src/config -ID:\Tornado\target/src/drv -DCPU=I80386 -P -x assembler-with-cpp -c -o romInit.o romInit.s
可見(jiàn)這個(gè)匯編文件也是調(diào)用cc進(jìn)行編譯 的,使用的選項(xiàng)為-x assembler-with-cpp,即用C預(yù)處理器進(jìn)行預(yù)處理。預(yù)處理后生成一個(gè)“純”匯編,放在一個(gè)臨時(shí)文件里,cc再調(diào)用匯編器對(duì)它進(jìn)行編譯。C 和匯編進(jìn)行混合的好處是可以共享一些宏定義并發(fā)揮C編譯器的靈活性,不好的是難于定位錯(cuò)誤。
【VxWorks初始化】


.data
■ 開(kāi)始數(shù)據(jù)段。以下內(nèi)容出現(xiàn)在數(shù)據(jù)段里。
.globl _copyright_wind_river
.long _copyright_wind_river
■ 申明(declare)全局變量_copyright_wind_river并使用它定義一個(gè)新變量。
■ 注意”.globl”是申明而非定義(相當(dāng)于C的extern)。_copyright_wind_river變量在Tornado的庫(kù)(對(duì)于 pc386,為[Tornado]/target/lib/libI80386gnuvx.a)中的一個(gè)模塊copyright.o中定義。
■ ”.long”定義一個(gè)32-bit的全局變量,變量的初始值為_(kāi)copyright_wind_river的地址。由于在Makefile中規(guī)定了romInit.o為第一個(gè)鏈接的模塊,所以這個(gè)無(wú)名變量將出現(xiàn)在數(shù)據(jù)段的最開(kāi)始。
#define _ASMLANGUAGE
■ 定義_ASMLANGUAGE宏。GNU編譯器cc看到這個(gè)定義后,會(huì)按照C的語(yǔ)法進(jìn)行預(yù)處理,所以能夠認(rèn)識(shí)C頭文件中定義的類型和宏。如果不定義_ASMLANGUAGE,以下的#include語(yǔ)句將無(wú)法編譯。
#include "vxWorks.h"
#include "sysLib.h"
#include "config.h"
■ 包含C的3個(gè)頭文件。vxWorks.h為系統(tǒng)頭文件;sysLib.h為系統(tǒng)提供給BSP的頭文件;config.h是BSP的頭文件。
.globl _romInit
.globl _sdata
■ 申明全局變量_romInit和_sdata。_romInit實(shí)際上是代碼的起始位置。
_sdata:
.asciz "start of data"
■ 定義一個(gè)以0結(jié)尾的字符串”start of data”。這個(gè)串出現(xiàn)在數(shù)據(jù)段的第一個(gè)無(wú)名變量之后。
.text
.align 4
■ .text開(kāi)始代碼段,以下內(nèi)容出現(xiàn)在代碼段里。.align 4指示編譯器調(diào)整當(dāng)前在.text段中的指針為2^4的倍數(shù)。編譯器進(jìn)行填充,使得下一條指令出現(xiàn)在能被16整除的地址上。對(duì)齊可使CPU取指令快一點(diǎn)。

_romInit:

■ 以下執(zhí)行的是VxWorks系統(tǒng)的第一條指令。此時(shí)CPU還處于實(shí)模式,程序只能訪問(wèn)1M內(nèi)存空間,缺省的指令為16-bit代碼。需要盡快將CPU切換到保護(hù)模式。
cli
jmp cold
■ 關(guān)中斷,跳轉(zhuǎn)到cold處。這是段內(nèi)相對(duì)跳轉(zhuǎn)。
.align 4, 0x90

■ 系統(tǒng)熱啟動(dòng)從_romWarmHigh或_romWarmLow開(kāi)始,參考sysLib.c中的sysToMonitor()。請(qǐng)自行分析熱啟動(dòng)過(guò)程。
_romWarmHigh:
cli
movl 4(%esp), %ebx
jmp warm
.align 4, 0x90

_romWarmLow:
cli
cld
movl $RAM_LOW_ADRS, %esi
movl $ROM_TEXT_ADRS, %edi
movl $ROM_SIZE, %ecx
shrl $2, %ecx
rep
movsl
movl 4(%esp), %ebx
jmp warm

.ascii "Copyright 1984-1996 Wind River System, Inc."
.align 4
■ 以上定義的版權(quán)申明字符串出現(xiàn)在代碼段中。
cold:
aword
word
lidt %cs:ROM_IDTR
aword
word
lgdt %cs:ROM_GDTR
■ 在實(shí)模式下的CS,DS,ES,F(xiàn)S,GS,SS等段寄存器的值*16就是段的基地址,而在保護(hù)模式下稱為selector(16位的段選擇子),指向全局描述符表GDT中的項(xiàng)(descriptor,段描述符,48位),段的基地址、大小以及屬性從段描述符中取得。在切換到保護(hù)模式前,需要準(zhǔn)備好 GDT。GDT在內(nèi)存中,由CPU的GDTR寄存器指定其基地址和大小。
所以在保護(hù)模式下,使用CS等寄存器作為GDT數(shù)組的索引,從表中獲得段的基地址。當(dāng)然這是由硬件自動(dòng)執(zhí)行的。
■ 在保護(hù)模式下,中斷向量表的基地址和大小必須由IDTR寄存器指定。
■ 這兩條指令裝載IDTR和GDTR寄存器。這兩個(gè)寄存器都是48位的,前16位是表的大小減1,后32位是表在內(nèi)存中的基地址。
■ aword和word指令前綴是做什么用的?這兩個(gè)前綴的機(jī)器碼分別為0x67和0x66。在32-bit代碼前加這樣的前綴可以讓它變?yōu)?6-bit代碼;在16-bit代碼前可以變?yōu)?2-bit代碼。
■ 什么是32-bit代碼和16-bit代碼?比如說(shuō)機(jī)器碼“89H,C3H”是表示“mov %eax, %ebx”還是表示“mov %ax, %bx”?(是的,這兩條語(yǔ)句的機(jī)器碼相同。否則指令數(shù)目就太多了?。?6-bit還是32-bit,這得看當(dāng)前代碼段的屬性是32位的還是16位的。段屬性在段描述符中。(一個(gè)結(jié)論是:保護(hù)方式未必是32-bit方式的,因?yàn)榭梢孕薷亩螌傩?。但是在?shí)模式下,并沒(méi)有段描述符,段寄存器中直接包含段值。 Intel的手冊(cè)說(shuō)缺省的操作數(shù)寬度和地址寬度總是16-bit的。)
操作數(shù)寬度屬性:指定操作數(shù)的寬度是32-bit的(例如%eax),還是16-bit的(例如%ax)。
地址寬度屬性:如果一條指令產(chǎn)生對(duì)存儲(chǔ)器的尋址,則指定地址寬度。
■ GNU編譯器缺省工作于32-bit匯編模式,就是說(shuō)它假定當(dāng)前指令為32-bit代碼。然而此時(shí)CPU還處于實(shí)模式,CPU缺省地認(rèn)為當(dāng)前指令為16-bit指令??梢宰孋PU在實(shí)模式下執(zhí)行32-bit的指令,方法就是加指令前綴。
■ 還有其它的指令前綴,參考CPU手冊(cè)。指令前綴只影響下一條指令。
■ ROM_IDTR和ROM_GDTR在pc.h中分別定義為0xAF和0xB5,分別指定要加載的IDTR和GDTR寄存器的值在當(dāng)前代碼段中存放的位置。當(dāng)然這是手工計(jì)算的結(jié)果。也許可以替換為_(kāi)romIdtr - _romStart和_romGdtr - _romStart。
movl %cr0, %eax
.byte 0x66
or $0x00000001, %eax
movl %eax, %cr0
jmp romInit1
■ 切換到保護(hù)模式。實(shí)際上很簡(jiǎn)單:把CR0寄存器最低位置1即可進(jìn)入保護(hù)模式。
■ .byte 66指令前綴(等效于word;不知道作者為什么不再使用word)指定32位操作數(shù)。如果沒(méi)有這個(gè)前綴,CPU在實(shí)模式下執(zhí)行”or $0x00000001, %eax”的效果將是”ax|=0x0001”。
■ jmp為段內(nèi)相對(duì)跳轉(zhuǎn)。切換到保護(hù)模式前的指令隊(duì)列中的內(nèi)容還是以前CPU預(yù)取的指令。利用jmp可以清空它。
romInit1:
.byte 0x66
mov $0x0010, %eax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
.byte 0x66
mov $ROM_STACK, %esp
■ 現(xiàn)在已進(jìn)入保護(hù)模式。然而各個(gè)段寄存器的值,以及它們的高速緩存寄存器中的值還是老的。把DS, ES, FS, GS, SS寄存器設(shè)為0x0010,即指向GDT的第2項(xiàng)(從0開(kāi)始),DPL=0。它們都指向一個(gè)段。把堆棧指針esp設(shè)為ROM_STACK。
■ 由于CS還是以前的值,意味著目前代碼段的屬性還是16-bit代碼。所以使用指令前綴以執(zhí)行32-bit代碼。
aword
word
ljmp $0x08, $ROM_TEXT_ADRS + ROM_INIT2
■ 執(zhí)行一個(gè)遠(yuǎn)程段間跳轉(zhuǎn)修改CS。CS的新值為0x08,即GDT的第1項(xiàng),DPL=0。修改CS時(shí)它的高速緩存寄存器也會(huì)自動(dòng)更新。以下將進(jìn)入到32-bit代碼模式。
■ ROM_INIT2在pc.h中定義為0xF0,也應(yīng)該是手工計(jì)算的結(jié)果,指示_romInit2相對(duì)于當(dāng)前代碼段的偏移。也許可以替換為_(kāi)romInit2 - _romStart + ROM_TEXT_ADRS。
_romIdtr:
.word 0x0000
.long 0x000000000
■ IDT(Interrupt Description Table),中斷描述符表,空的。
_romGdtr:
.word 0x0027
.long ROM_TEXT_ADRS + ROM_GDT
■ 將要加載的GDTR寄存器的值。ROM_GDT在pc.h中定義為0xC0。也許可以這樣寫:
.word _romGdtEnd - _romGdt - 1
.long _romGdt - _romStart + ROM_TEXT_ADDR
讓編譯器給我們計(jì)算,這樣更靈活一些。
.align 4, 0
_romGdt:

.word 0x0000
.word 0x0000
.byte 0x00
.byte 0x00
.byte 0x00
.byte 0x00

.word 0xFFFF
.word 0x0000
.byte 0x00
.byte 0x9A
.byte 0xCF
.byte 0x00

.word 0xFFFF
.word 0x0000
.byte 0x00
.byte 0x92
.byte 0xCF
.byte 0x00

.word 0xFFFF
.word 0x0000
.byte 0x00
.byte 0x9A
.byte 0xCF
.byte 0x00

.word 0xFFFF
.word 0x0000
.byte 0x00
.byte 0x9A
.byte 0xCF
.byte 0x00
■ 以下的代碼運(yùn)行于保護(hù)模式,各個(gè)段寄存器已包含合適的值。
.align 4,0x90
_romInit2:
cli
mov $ ROM_STACK,%esp
call _romA20on
movl $ BOOT_COLD,%ebx
warm:
movl $_romGdtr,%eax
subl $_romInit,%eax
addl $ ROM_TEXT_ADRS,%eax
pushl %eax
call _romLoadGdt
movl $ STACK_ADRS,%esp
movl $0,%ebp
pushl $0
popfl
pushl %ebx
cld
movl $ ROM_TEXT_ADRS,%esi
movl $_romInit,%edi
movl $_end,%ecx
subl %edi,%ecx
shrl $2,%ecx
rep
movsl
movl $_romStart,%eax
call *%eax

_romInitHlt:
hlt

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
基于VxWorks的BSP概念與開(kāi)發(fā)
MPC860上電初始化流程分析 - 我的文章 - VxWorks
Essential Linux Device Driver附錄A . Linux匯編
Linux線程TLS(Thread
淺析Linux計(jì)算機(jī)工作機(jī)制
換種方法學(xué)操作系統(tǒng)輕松入門Linux內(nèi)核(與圖靈機(jī)不同馮諾依曼機(jī)是一個(gè)實(shí)際的體系結(jié)構(gòu))CPU就是從EIP指向的那個(gè)地址取過(guò)來(lái)一條指令執(zhí)行
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服