如果我們將兩個(gè)4G內(nèi)存插入內(nèi)存插槽,得到的內(nèi)存地址空間是0到8G嗎?是不是0到4G是第一根內(nèi)存,4到8G是第二根內(nèi)存呢?實(shí)際情況相差甚遠(yuǎn),內(nèi)存在物理地址空間的映射是分散的。一部分原因是4G以下有Memory map IO(mmio)空間和PCIe的配置空間,另一個(gè)原因是Interleaving會(huì)打撒內(nèi)存地址到各個(gè)Channel、DIMM甚至是Rank和bank上。今天我們就一起來了解一下x86系統(tǒng)的地址空間分布。
物理地址空間
一個(gè)典型的物理地址空間是這樣的:
其中只有灰色部分是真正的內(nèi)存,其余都是MMIO。而內(nèi)存被分為High DRAM和Low DRAM,如圖:
為什么要把內(nèi)存強(qiáng)行分割成兩塊呢?因?yàn)闅v史的包袱。最早內(nèi)存都很小,32位的地址(4G)空間看起來永遠(yuǎn)也用不完,低地址被分配給內(nèi)存用,高地址就自然而然被分配用來給Memory map IO。既然已經(jīng)分給它們了,為了兼容以前的驅(qū)動(dòng),這一塊就被固定下來。再有內(nèi)存就只能從4G以上分配了。
Low MMIO和High MMIO
Low MMIO結(jié)構(gòu)如下圖:
其中有幾塊要特別說明一下:
1.Boot Vector的空間是BIOS內(nèi)容映射的地址,它的大小是可以調(diào)節(jié)的,為了滿足不同大小的BIOS。
2.Local APIC是APIC中斷模式各個(gè)內(nèi)核local APIC寄存器的映射地址。
3.PCI ECAM也有叫做PCIBAR,是PCIe配置地址空間的映射地址。它的起始地址可調(diào),臺(tái)式機(jī)BIOS一般會(huì)把它設(shè)置得很高,這樣4G以下內(nèi)存會(huì)比較大,方便32位Windows使用。舉個(gè)例子,如果我們把PCIe BAR(BEGREG)設(shè)為0x80000000,那么盡管插了8G DIMM,4G以下也不會(huì)超過2G的內(nèi)存可以使用,而2到8G的真實(shí)內(nèi)存都被映射到在4G地址空間以上了,而這些是32位Windows使用不了的。所以有的主板運(yùn)行32位操作系統(tǒng)發(fā)現(xiàn)可用內(nèi)存小了一大塊就是這個(gè)原因。它的大小可以修改,一般可以設(shè)為64MB和128MB。
High MMIO被BIOS保留作為64位mmio分配之用,例如PCIe的64位BAR等。
Low DRAM和High DRAM
4G以下內(nèi)存最高地址叫做BMBOUND,也有叫做Top of Low Usable DRAM (TOLUD) 。BIOS也并不是把這些都報(bào)告給操作系統(tǒng),而是要在里面劃分出一部分給核顯、ME和SMM等功能:
紅框中是在low DRAM被“偷”的部分
4G以上的內(nèi)存最高端叫做Top of Up Usable DRAM (TOUUD) ,再上面就是High MMIO了。
1MB以下比較特殊,里面全部都是已經(jīng)被淘汰的傳統(tǒng)BIOS和DOS關(guān)心的內(nèi)容,我們叫它DOS Space或者Legacy Region:
在那里,我們習(xí)慣用傳統(tǒng)的實(shí)模式地址來劃分它們的具體內(nèi)容:
1.0~640KB,傳統(tǒng)DOS空間。
2.A段和B段,傳統(tǒng)SMM空間。VGA的MMIO也被映射到這里,可以通過寄存器切換。
3.C段和D段,legacy opROM映射空間和EBDA空間。
4.E段和F段,BIOS空間的Lower和Upper映射地址。BIOS的rom內(nèi)容也會(huì)被映射到這里,方便Legacy BIOS實(shí)模式跳轉(zhuǎn)到保護(hù)模式。
內(nèi)存的Interleave
從前面可以看出內(nèi)存在地址空間上被拆分成兩塊:Low DRAM和High DRAM。那么在每塊地址空間上分配連續(xù)嗎?現(xiàn)代內(nèi)存系統(tǒng)在引入多通道后,為了規(guī)避數(shù)據(jù)的局部性(這也是Cache為什么起作用的原因)對多通道性能的影響,BIOS基本缺省全部開啟了Interleaving,過去美好的DIMM 0和DIMM 1挨個(gè)連續(xù)分配的日子一去不復(fù)返了。
什么是Interleaving?簡單來說,就是讓內(nèi)存交錯(cuò)起來,如下面的動(dòng)圖:
這是一個(gè)bank層級(jí)的模4的interleaving。在桌面電腦上,常見的還有Channel級(jí)的、DIMM級(jí)的和Rank級(jí)的。
服務(wù)器上Interleaving更是不可或缺,它的粒度更細(xì),可以達(dá)到數(shù)十bytes層級(jí)的interleave,它和內(nèi)存的其他特性,如類似磁盤陣列RAID的內(nèi)存spare, mirror特性,構(gòu)成了復(fù)雜異常的內(nèi)存映射系統(tǒng)。在BIOS里面,臺(tái)式機(jī)/筆記本內(nèi)存映射相對簡單,只有一個(gè)大表和數(shù)十個(gè)寄存器;而在服務(wù)器BIOS中,有數(shù)個(gè)相互關(guān)聯(lián)的大表和寄存器陣列來解碼(decode)內(nèi)存的請求,代碼的硬件邏輯也是相當(dāng)復(fù)雜。關(guān)于它,我會(huì)有一篇專欄文章討論地址譯碼和地址反向解碼,詳細(xì)內(nèi)容那里再說,這里只需要知道,物理內(nèi)存分布在各個(gè)DIMM上就夠了。
物理地址到內(nèi)存單元的反推
BIOS實(shí)際上一手導(dǎo)演的內(nèi)存的分配,它當(dāng)然可以從任何物理地址反推回內(nèi)存的單元地址。我們可以用下面一組數(shù)據(jù)來唯一確定某個(gè)內(nèi)存單元:
Channel #;DIMM #; Rank #;Bank #;Row #;Column #
在內(nèi)存分配表缺失的情況下,BIOS甚至可以通過它填過的寄存器重建這個(gè)映射表。但實(shí)際上BIOS并不希望一般用戶知道這些信息,因?yàn)橛邪踩詥栴}。
暴露內(nèi)存信息容易招來內(nèi)存?zhèn)刃诺拦簦⊿ide Channel),比較有名的有Row hammer攻擊。簡單的來說它是通過反復(fù)寫某個(gè)內(nèi)存單元,借助內(nèi)存的特性,希望影響相鄰Row/Column的內(nèi)容。
有些情況確實(shí)需要知道這些信息,就是內(nèi)存出錯(cuò)的時(shí)候。和大家想象的不同,內(nèi)存是會(huì)出錯(cuò)的。尤其云服務(wù)器中內(nèi)存的出錯(cuò)是十分頻繁的。出錯(cuò)起來也千奇百怪,開始可能是偶爾的隨機(jī)錯(cuò)誤,經(jīng)過ECC等校正后,就再也不會(huì)復(fù)現(xiàn);而有時(shí)是某個(gè)Bit總是出錯(cuò),進(jìn)而慢慢的整個(gè)row、column或者相鄰的cell開始出錯(cuò),從可以糾正的錯(cuò)誤變成不可修正的錯(cuò)誤,導(dǎo)致服務(wù)器必須停機(jī)。這時(shí)候就必須知道哪個(gè)內(nèi)存壞了,進(jìn)而換掉它。
報(bào)告給操作系統(tǒng),但這個(gè)信息里面只有物理地址,如何才能知道是哪個(gè)內(nèi)存單元壞了呢?在Linux上面可以通過edca(參考資料4),有編程經(jīng)驗(yàn)的同學(xué)可以通過edca的程序接口(參考資料3),可以得到更加豐富的信息。
如何關(guān)掉Interleaving
對內(nèi)存有特殊需求的朋友,如果希望內(nèi)存連續(xù),可以在BIOS里面關(guān)閉所有的Interleaving來達(dá)成這個(gè)目標(biāo):
注意是所有的。之后可以通過SMBIOS來看到內(nèi)存分布信息(dmidecode)。
結(jié)論
BIOS作為內(nèi)存的大管家,也負(fù)責(zé)內(nèi)存的分配和映射memory map。它會(huì)把這些信息通過E820, GetMemoryMap函數(shù)和SMBIOS傳遞給操作系統(tǒng)。操作系統(tǒng)在此基礎(chǔ)上再建立頁表,產(chǎn)生虛擬地址。
-
寄存器
+關(guān)注
關(guān)注
31文章
5359瀏覽量
120812 -
Linux系統(tǒng)
+關(guān)注
關(guān)注
4文章
595瀏覽量
27451 -
DRAM芯片
+關(guān)注
關(guān)注
1文章
84瀏覽量
18038 -
PCIe接口
+關(guān)注
關(guān)注
0文章
120瀏覽量
9759 -
DOS系統(tǒng)
+關(guān)注
關(guān)注
0文章
9瀏覽量
1414
發(fā)布評(píng)論請先 登錄
相關(guān)推薦
評(píng)論