顯示具有 PC相關知識建立 標籤的文章。 顯示所有文章
顯示具有 PC相關知識建立 標籤的文章。 顯示所有文章

2011年11月29日 星期二

x64存儲管理機制初窺

x64存儲管理機制初窺
x64存儲管理機制,經prolj和mik指點,去找intel手冊和AMD手冊看,看完之後把我的理解寫下,
如有什麼理解偏差之處,還望各位不要笑話。
1.長模式(long mode)
   在AMD64架構的長模式中包括兩個子模式:64bit模式和compatibility模式。
   ● 64bit模式:在此模式中虛擬位址空間使用平坦(flat)模式,段寄存器包括CS,DS,ES,SS全部清零(FS,GS除外,在線性位址計算時,提供額外的base寄存器定址某些OS的系統資料結構),能為64bit的OS和應用程式提供64位元定址支援。
   ●compatiblity模式:在此模式中使用與lagecy保護模式一樣的存儲管理模式,為的是平滑運行32bit和16bit的應用程式,無需重新編譯,注意:在長模式中不支援真實模式和虛擬8086模式!!











由於在64bit模式下使用flat模式,所以無lagecy保護模式下的分段管理模式,所以虛擬位址直接對應線性位址。所以x64的分頁管理模式才是64bit下的重頭戲
  
   2.x64分頁管理模式
   如下圖,是x86-64下的所有頁大小和物理位址大小的匯總.










在x64下,理論上可以通過使用PAE(實體位址擴充)分頁結構支援64bit的線性位址到52bit物理位址的映射的,但在對這一架構的首次實現中,只實現了48位元的線性位址到40位元物理位址的映射。現在你可以通過CPUID指令查看自己的cpu所支援的最大物理位址(MAXPHYDDR).
   大家一定還記得在lagecy保護模式下通過PAE功能來訪問超過32bit(36bit)的物理位址,但是在x64模式下的PAE與先前的PAE是不一樣的!!
   從線性位址到物理位址的轉換中用到了四級頁資料結構,一個新的頁表資料結構---PML4被引入用來指向頁目錄指標表。PML4表只能在x64模式下使用。而且頁目錄表指標從原來的4個項增加到了512個,所以要從線性位址中分配9bit用來索引PDP表(原來是2bit)。
   PDE和PTE的大小保持不變。所以我們可以看到PML4+PDP+PDE+PTE+page offset=48bit,高16bit保留(其實是用以符號擴展,下面將看到符號擴展的用途)。
   CR3指向了PML4的基底位址。
   需要注意的是在使用x64模式之前,必須使CR4.PAE=1(PAE用來擴展PDE和PTE至64bit)。如果你在未使CR4.PAE=1之前,企圖開啟x64模式的話,會引發#GP異常。
   我們從上圖還可以看到頁大小的選擇完全取決於PDE.PS(但我並沒有在文檔中看到ps位,是直接在文檔中置1或0),無視CR4.PSE的存在。
   2.1x64分頁管理(4kb)
   上圖再說




















●sign extended--符號擴展位元
   ●PML4 entry--在線性位址39~47bit用於索引PML4 entry,指向PDP
   ●PDP entry--在線性位址的30~38bit用來索引PDP entry,指向PDE
   ●PDE entry--在線性位址的21~29bit用來索引PDEentry,指向PTE
   ●PTE entry--在線性位址的12~20bit用來索引PTE entry,指向page offset
   ●page offset--在線性位址的0~11bit提供在頁中的offset
   2.2x64分頁管理(2mb)




















我們可以看到與4kb的頁相比少了PTE,page offset從原來的12bit增加到了21bit下面我們來看看各分頁表項目的內部結構.
























(4kB)上圖看到,用上述方法可以得到512×512×512×512=2^36個頁面,2^36*4kb=2^48個線性位址.



















上圖看到,用上述方法可以得到512×512×512=2^27個頁面,2^27*2mb=2^48個線性位址 0bit:P位,即存在位,表示由項所指的頁面或頁表當前是否載入到了物理記憶體中,如不存在,可以通過引發#PF異常從磁片中載入到物理記憶體中
   1bit:R/W,即讀寫位,為頁表指定讀寫特權,當置位時可讀可寫;清零是唯讀
   2bit:使用者/系統位元,即為頁表指定系統還是普通使用者特權
   3bit:頁面通寫,指定快取記憶體寫策略是回寫還是通寫
   4bit:快取記憶體禁止位,當置位元時禁止相關的頁面和頁表進行快取記憶體,反之,可以
   5bit:訪問位,當置位時表示已經被訪問,反之,沒有
   6bit(非PTE或PDE(2MB)):可用位
   6bit(PTE或PDE(2MB)):D位,dirty,即髒位,置位元時表示頁面被寫過
   7~8bit(非PTE或PDE(2MB)):0
   avail:系統程式師可用
   G:全域標誌
   PAT:頁表屬性
   各種base address是用來得到下一級表的基底位址的,最後的物理位址=page base address*2^12(2^21)+2^12(2^21),而page base address的大小取決於你的cpu的最大物理位址了。
   3.最後,我來看一看sign extended會形成什麼效果。
   由於sign extended的作用會將線性位址分成相同大小的兩段,從0至00007FFF`FFFFFFFF,以及從 FFFF8000`00000000至FFFFFFFF`FFFFFFFF總計256TB的地址範圍,這非常符合作業系統的習慣。
   這種“古怪”的規則為日後擴展到真正的64位定址保留了一個重要的特性:很多的作業系統(包括但不限於Windows NT系列)將位址空間的高半部分(被稱作內核空間)留給自己,將低半部分(使用者空間)留給應用程式碼、用戶態棧、堆和其他數據區。這種設計保證了每一個符合AMD64的實現都擁有兩個記憶體片段:低半段從00000000`00000000開始,隨著更多的虛擬位址位元變得可用而“向上生長”;高半部分被“懸掛”在位址空間的頂部而“向下生長”。同樣,將未被使用的位址位元內容固定下來防止被作業系統用作標誌位元、特權級標號等其他用途,是為了避免當架構擴展至52,56, 60 和64位的時候出現問題。















參考資料:
   1.http://zh.wikipedia.org/zh-cn/X86-64
   2.intel手冊
   3AMD手冊
--> 閱讀更多...

2010年8月12日 星期四

關於APIC的見解

APIC(高級可編程中斷控制器)對計算機來講有兩個作用, 管理IRQ的分配,可以把傳統的16個IRQ擴展到24個(傳統的管理方式叫PIC),以適應更多的設備。
管理多CPU。由於Nf2主板並不支援多CPU,所以,APIC關閉直接的影響是減少了可用的IRQ。 不過,如果板卡不是非常多的話,關閉 APIC對系統是沒有什麼影響的。要實現SMP功能,我們使用的CPU必須具備以下要求:CPU 內部必須內置APIC單元。Intel 多處理規範的核心就是高級可編程中斷控制器(Advanced Programmable Interrupt Controllers–APICs)的使用。CPU通過彼此發送中斷來完成它們之間的通信。通過給中斷附加動作(actions),不同的CPU可以在某種程度上彼此進行控制。每個CPU有自己的APIC(成為那個CPU的本地APIC),並且還有一個I/O APIC來處理由I/O設備引起的中斷,這個I/O APIC是安裝在主板上的,但每個CPU上的APIC則不可或缺,否則將無法處理多CPU之間的中斷協調。以上內容截自http://boy-asmc.blogspot.com/2009/11/acpi-vs-apic.html 。
一般而言,若要得知BIOS是否支援APIC時會先到e0000H~f0000h之間尋找20445352h(" DSR")及20525450h(" RTP")字樣;若找到後接下來CHECK接下來的20Bytes其check_sum是否等於0。接著以目前的es:dword ptr[10h]的值為index並以es:word ptr[index+4]為cx當成loop迴圈,來搜尋"CIPA"字樣,便可找到APIC Table。
更詳細的內容請參考Intel64 and IA-32 Architectures Software Developer's Manual-3A.pdf 之Chapter 10。另外參考:
http://www.cs.usfca.edu/~cruse/cs630f06/lesson27.ppt
http://faculty.qu.edu.qa/rriley/cmpt507/minix/apic_8c-source.html
--> 閱讀更多...

2010年5月6日 星期四

linux SMP 啟動過程學習筆記

SMP 硬體體系結構:
對於 SMP 最簡單可以理解為系統存在多個完全相同的 CPU ,所有 CPU 共用匯流排,擁有自己的寄存器。對於記憶體和外部設備訪問,由於共用匯流排,所以是共用的。 Linux 作業系統多個 CPU 共用在系統空間上映射相同,是完全對等的。
由於系統中存在多個 CPU ,這是就引入一個問題,當外部設備產生中斷的時候,具體有哪一個 CPU 進行處理?
為此, intel 公司提出了 IO APCI 和 LOCAL APCI 的體系結構。
IO APIC 連接各個外部設備,並可以設置分發類型,根據設定的分發類型,中斷信號發送的對應 CPU 的 LOCAL APIC 上。
LOCAL APIC 負責本地 CPU 的中斷處理, LOCAL APIC 不僅可以接受 IO APIC 的中斷,也需要處理本地 CPU 產生的異常。同時 LOCAL APIC 還提供了一個計時器。
如何確定那個 CPU 是引導 CPU ?
根據 intel 公司中的資料,系統上電後,會根據 MP Initialization Protocol 隨機選擇一個 CPU 作為 BSP ,只有 BSP 會運行 BIOS 程式,其他 AP 都進入等待狀態, BSP 發送 IPI 中斷觸發後才可以運行。具體的 MP Initialization Protocol 細節,可以參考 Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide, Part 1 第 8 章。
引導 CPU 如何控制其他 CPU 開始運行?
BSP 可以通過 IPI 消息控制 AP 從指定的起始位址運行。 CPU 中集成的 LOCAL APIC 提供了這個功能。可以通過寫 LOCAL APIC 中提供的相關寄存器,發送 IPI 消息到指定的 CPU 上。
如何獲取系統硬體 CPU 資訊的?
在系統初始化後,硬體會在記憶體的規定位置提供關於 CPU ,匯流排 , IO APIC 等的資訊,即 SMP MP table 。在 linux 初始化的過程,會讀取該位置,獲取系統相關的硬體資訊。
2. linux SMP 啟動過程流程簡介
setup_arch()
setup_memory();
reserve_bootmem(PAGE_SIZE, PAGE_SIZE);
find_smp_config(); // 查找 smp mp table 的位置
smp_alloc_memory();
trampoline_base = (void *) alloc_bootmem_low_pages(PAGE_SIZE); // 分配 trampoline ,用於啟動 AP 的引導代碼。
get_smp_config(); // 根據 smp mp table ,獲取具體的硬體資訊
trap_init()
init_apic_mappings();
mem_init();
zap_low_mappings(); 如果沒有定義 SMP 的話,清楚用戶空間的位址映射。
rest_init();
kernel_thread(init, NULL, CLONE_FS CLONE_SIGHAND);
init();
set_cpus_allowed(current, CPU_MASK_ALL);
smp_prepare_cpus(max_cpus);
smp_boot_cpus(max_cpus);
connect_bsp_APIC();
setup_local_APIC(); // 初始化 BSP 的 LOCAL APCI 。
map_cpu_to_logical_apicid();
針對每個 CPU 調用 do_boot_cpu(apicid, cpu)
smp_init(); // 每個 CPU 開始進行調度
trampoline.S AP 引導代碼,為 16 進制代碼,啟用保護模式
head.s 為 AP 創建分頁管理
initialize_secondary 根據之前 fork 創建設置的資訊,跳轉到 start_secondary 處
start_secondary 判斷 BSP 是否啟動,如果啟動 AP 進行任務調度。
3. 代碼學習總結
find_smp_config(); ,查找 MP table 在記憶體中的位置。具體協定可以參考 MP 協定的第 4 章。
這個表的作用在於描述系統 CPU ,匯流排, IO APIC 等的硬體資訊。
相關的兩個總體變數: smp_found_config 是否找到 SMP MP table , mpf_found SMP MP table 的線性位址。
smp_alloc_memory() 為啟動 AP 的啟動程式分配記憶體空間。相關總體變數 trampoline_base ,分配的啟動位址的線性位址。
get_smp_config() 根據 MP table 中提供的內容,獲取硬體的資訊。
init_apic_mappings(); 獲取 IO APIC 和 LOCAL APIC 的映射位址 。
zap_low_mappings(); 如果沒有定義 SMP 的話,清楚用戶空間的位址映射。將 swapper_pg_dir 中表項清零。
setup_local_APIC(); 初始化 BSP 的 LOCAL APCI 。
do_boot_cpu(apicid, cpu)
idle = alloc_idle_task(cpu);
task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL, NULL, 0);
init_idle(task, cpu);
將 init 進程使用 copy_process 複製,並且調用 init_idle 函數,設置可以運行的 CPU 。
idle->thread.eip = (unsigned long) start_secondary;
修改 task_struct 中的 thread.eip ,使得 AP 初始化完成後,就運行 start_secondary 函數。
start_eip = setup_trampoline();
調用 setup_trampoline() 函數,複製 trampoline_data 到 trampoline_end 之間的代碼到 trampoline_base 處, trampoline_base 就是之前在 setup_arch 處申請的記憶體。 start_eip 返回值是 trampoline_base 對應的物理位址。
smpboot_setup_warm_reset_vector(start_eip); 設置記憶體 40:67h 處為 start_eip 為啟動地址。
wakeup_secondary_cpu(apicid, start_eip); 在這個函數中通過操作 APIC_ICR 寄存器, BSP 向目標 AP 發送 IPI 消息,觸發目標 AP 從 start_eip 位址處,從實模式開始運行。
trampoline.S
ENTRY(trampoline_data)
r_base = .
wbinvd # Needed for NUMA-Q should be harmless for others
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
cli # We should be safe anyway
movl $0xA5A5A5A5, trampoline_data - r_base
這個是設置標識,以便 BSP 知道 AP 運行到這裏了。

lidtl boot_idt - r_base # load idt with 0, 0
lgdtl boot_gdt - r_base # load gdt with whatever is appropriate
載入 ldt 和 gdt
xor %ax, %ax
inc %ax # protected mode (PE) bit
lmsw %ax # into protected mode
# flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
ljmpl $__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET)
啟動保護模式,跳轉到 startup_32_smp 處
# These need to be in the same 64K segment as the above;
# hence we don't use the boot_gdt_descr defined in head.S
boot_gdt:
.word __BOOT_DS + 7 # gdt limit
.long boot_gdt_table-__PAGE_OFFSET # gdt base
boot_idt:
.word 0 # idt limit = 0
.long 0 # idt base = 0L
.globl trampoline_end
trampoline_end:
在這段代碼中,設置標識,以便 BSP 知道該 AP 已經運行到這段代碼,載入 GDT 和 LDT 表基址。
然後啟動保護模式,跳轉到 startup_32_smp 處。
Head.s 部分代碼:
ENTRY(startup_32_smp)
cld
movl $(__BOOT_DS),%eax
movl %eax,%ds
movl %eax,%es
movl %eax,%fs
movl %eax,%gs
xorl %ebx,%ebx
incl %ebx
如果是 AP 的話,將 bx 設置為 1
movl $swapper_pg_dir-__PAGE_OFFSET,%eax
movl %eax,%cr3 /* set the page table pointer.. */
movl %cr0,%eax
orl $0x80000000,%eax
movl %eax,%cr0 /* ..and set paging (PG) bit */
ljmp $__BOOT_CS,$1f /* Clear prefetch and normalize %eip */
啟用分頁,
lss stack_start,%esp
使 esp 執行 fork 創建的進程內核堆疊部分,以便後續跳轉到 start_secondary
#ifdef CONFIG_SMP
movb ready, %cl
movb $1, ready
cmpb $0,%cl
je 1f # the first CPU calls start_kernel
# all other CPUs call initialize_secondary
call initialize_secondary
jmp L6
1:
#endif /* CONFIG_SMP */
call start_kernel
如果是 AP 啟動的話,就調用 initialize_secondary 函數。
void __devinit initialize_secondary(void)
{
/*
* We don't actually need to load the full TSS,
* basically just the stack pointer and the eip.
*/
asm volatile(
"movl %0,%%esp\n\t"
"jmp *%1"
:
:"r" (current->thread.esp),"r" (current->thread.eip));
}
設置堆疊為 fork 創建時的堆疊, ip 為 fork 時的 ip ,這樣就跳轉的了 start_secondary 。
start_secondary 函數中處理如下:
while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
rep_nop();
進行 smp_commenced_mask 判斷,是否啟動 AP 運行。 smp_commenced_mask 在 smp_init() 中設置。
cpu_idle();
如果啟動了,調用 cpu_idle 進行任務調度。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/jemmy858585/archive/2009/09/01/4509375.aspx
--> 閱讀更多...

2009年5月9日 星期六

AMD64 & Intel EM64T


此圖是從intel datasheet:Intel64 and IA-32 Architectures Software Develops Manual Volume3A所截取下來,從這張圖就可知道CPU如何在各模式之間切換;及為什麼可以作到向下相容的架構。
圖二
圖一
AMD公司設計,可以在同一時間內處理64位的整數運算,並兼容于X86-32架構。其中支持64位邏輯定址,同時提供轉換為32位定址選項;但數據操作指令默認為32位和8位,提供轉換成64位和16位的選項;支持常規用途暫存器,如果是32位運算操作,就要將結果擴展成完整的64位。這樣,指令中有“直接執行”和“轉換執行”的區別,其指令字段是8位或32位,可以避免字段過長。
x86-64(也叫AMD64)的產生也並非空穴來風,x86處理器的32bit尋址空間限制在4GB內存,而IA-64的處理器又不能兼容x86。AMD充分考慮顧客的需求,加強x86指令集的功能,使這套指令集可同時支持64位的運算模式,因此AMD把它們的架構稱之為x86-64。在技術上AMD在x86-64架構中為了進行64位運算,AMD為其引入了新增了R8-R15通用暫存器作為原有X86處理器暫存器的擴充,但在而在32位環境下並不完全使用到這些暫存器。原來的暫存器諸如EAX、EBX也由32位擴張至64位。在SSE單元中新加入了8個新暫存器以提供對SSE2的支持。暫存器數量的增加將帶來性能的提升。與此同時,為了同時支持32和64位代碼及暫存器,x86-64架構允許處理器工作在以下兩種模式︰Long Mode(長模式)和Legacy Mode(傳統模式),Long模式又分為兩種子模式(64bit模式和Compatibility mode兼容模式)。該標準已經被引進在AMD伺服器處理器中的Opteron處理器。
而今年也推出了支持64位的EM64T技術,再還沒被正式命為EM64T之前是IA32E,這是英特爾64位擴展技術的名字,用來區別X86指令集。Intel的EM64T支持64位sub-mode,和AMD的X86-64技術類似,採用64位的線性平面尋址,加入8個新的通用暫存器(GPRs),還增加8個暫存器支持SSE指令。與AMD相類似,Intel的64位技術將兼容IA32和IA32E,只有在營運64位作業系統下的時候,才將會採用IA32E。IA32E將由2個sub-mode組成︰64位sub-mode和32位sub-mode,同AMD64一樣是向下兼容的。Intel的EM64T將完全兼容AMD的X86-64技術。現下Nocona處理器已經加入了一些64位技術,Intel的Pentium 4E處理器也支持64位技術。
應該說,這兩者都是兼容x86指令集的64位微處理器架構,但EM64T與AMD64還是有一些不一樣的地方
AMD的K8不是真正的64bit處理器,其和Intel的EM64T處理器一樣,不是真正的64bit處理器。Microsoft的WINXP64bit也不是真正意義上的64bit作業系統。真正64bit系統(硬體和軟體系統)出來的時候,現下這些所謂的64bit全部會淘汰,而這段時間會相當長,至少三年內難以實現;況且配件的更新速度很快,只要用的順手,何必在意以後會怎樣。順便說一下,現下的K8實際上是40bit處理器,而非64bit處理器;EM64T實際上是32bit處理器,只是在物理內存尋址上擴展到36bit。
AMD64 及 EM64T 倒底誰是一顆真正的 64 bit處理器,不用太在意, 這兩者都是由 32bit 處理器改進而來, 前陣子在 bbs 的 hardware 版, 為了AMD64 是不是創新的架構, 爭論了許久. 不過, 實際使用上, AMD64 不論是要當 32bit或 64 bit處理器來用, 算是不錯, 效能好, 溫度又低!

由 Intel EM64T 技術談 64 位元 CPU
由於軟體的功能越來越強大且多元化,所消耗的系統資源相對的也越多,因此在軟體的功能不斷提升的同時,硬體的處理能力也就捉襟見拙。而新技術不斷的發展,除了代表科技的進步外,也因應這必然的趨勢,造就了電腦平台的變革 —DDRⅡ、PCI Express、Hyper Threading 與 EM64T 等。
一、何謂 64 位元 CPU我們知道一個功能強大的軟體其實是由無數行的程式所組合而成,每一行的程式碼均會透過編譯器編譯成數筆資料,送到 CPU 內部的暫存器中等待執行。而所謂的 64 位元也就是在這資料的寬度、暫存器的大小以及執行指令的長度均為 64 位元,另外在記憶體的定址能力同樣也為 64 位元。
二、64 位元 CPU 的發展Intel CPU 的發展從 80386 之後便演進為 32 位元,到 1994 年 Intel 與 HP 共同開發 VLIW(Very Long Instruction Word)架構的 Itanium、Itanium2 的 IA-64 CPU,希望能將 HP 的 PA-RISC、COMPAQ 的 Alpha 以及 x86 架構的 PC 作一整合,以期降低研發高階伺服器處理器成本,並能跨平台的執行不同的作業系統。只是因為 Itanium、Itanium2 的 CPU 使用的是 VLIW 架構,雖然在執行 64 位元的作業系統與應用程式非常順暢,但於 32 位元的作業系統與應用程式中必須透過指令轉譯的方式來執行,導致在 32 位元的環境下效能不彰,因此發展上是叫好不叫座。在 64 位元 CPU 沈潛好一段時間之後,AMD 於 2003 年四月推出 64 位元 x86 架構的處理器 Opteron,以及 Apple 推出 PowerPC G5 的 RISC CPU,既可以執行 64 位元作業系統與應用程式,亦可向下相容於原本 32 位元的作業系統與應用程式,一時間 64 位元處理器的話題又熱絡起來。而 Intel 為了不讓競爭對手專美於前,於 2004 年春季 IDF 論壇中發表了 Intel 64bit Extension Technology 的新技術,並於 4 月份正式定名為 Intel Extended Memory 64 Technology(EM64T),並採用被稱之為 IA-32e 的新操作模式。
三、EM64T 技術Intel EM64T 是為了強化 IA-32 架構所發展的新技術。包含此技術的 IA-32 處理器除了可向下相容於現存的 32 位元軟體,並賦予軟體存取更多記憶體空間。並且允許那些開發於 32 位元定址模式下的軟體擁有執行於 64 位元定址空間的能力。相較於之前 IA32,擁有 EM64T 的 IA32e 最大的不同是將記憶體定址能力由原本 2 的 32 次方提升到 2 的 64 次方,也就是 18446744TB。
四、包含 EM64T 技術處理器的執行模式包含 IA32e 的處理器可執行在 Legacy IA-32 Mode 與 IA-32e Mode。IA-32e Mode 又包含了兩種子模式:1. Compatibility Mode:允許 64 位元的作業系統在不做任何的變動下執行大多數原生的 32 位元軟體。2. 64-bit Mode:允許 64 位元作業系統執行那些存取 64 位元位址空間的應用程式。
五、64-bit Mode 是用來在 64 位元作業系統下執行 64 位元應用程式,包含下列幾項特性:● 64 位元線性定址。● 8 個全新的一般暫存器(General-Purpose Register)。● 8 個全新 Streaming SIMD Extensions(SSE)暫存器支援 SSE、SSE2與SSE3。● 64 位元寬度的 GPR 與指令指標● 相同的 byte-register addressing● 更快速的中斷優化機制● 全新的指令指標相對定址模式64-bit Mode 可透過 64 位元作業系統藉由分割程式碼的準則來啟動。初始定址大小為 64 位元,初始運算元大小為 32 位元。
六、在 Compatibility Mode 中,絕大部分的 16 位元或 32 位元應用程式均可在不重新編譯的狀況下執行於 64 位元作業系統中。相同於 64-bit Mode,Compatibility Mode 可透過 64 位元作業系統藉由分割程式碼的準則來啟動。也就是說在同一時間中,64 位元應用程式也可被執行於 64-bit Mode,而不需重新編譯。
七、Legacy IA-32 Mode 包含保護模式、真實位址模式或是虛擬 8086 模式。針對這些模式撰寫的軟體,EM64T 的處理器均有完整的相容性。
上圖一列出 EM64T 處理器在不同模式下的差異:
上面圖二列出了在不同模式中所支援的暫存器類別:
八、64 位元處理器的迷思是不是購買了 64 位元處理器,相對的執行速度就是原本 32 位元的兩倍?其實以目前的作業系統 Windows XP 或是 Windows 2000 均為 32 位元的作業系統,而應用程式部分亦為 32 位元,也因此在程式碼分割與執行指令上仍為 32 位元寬,而 CPU 資料處理部分仍為 32 位元,也因此與目前的 IA-32 處理器並無差別。在未來 Windows XP 64-bit Edition for Extended System 上市後搭配 64 位元的應用程式,在效能方面才能有所提升。
--> 閱讀更多...

2009年4月14日 星期二

●符合SMBIOS規範的電腦系統訊息獲取方法

以下這篇有關smbiosㄉ文章寫ㄉ很詳細,貼在自己ㄉ部落格是因為工作會常用到,怕說以後會找不到這份資料。
符合SMBIOS規範的電腦系統訊息獲取方法

作者:ramble(如需轉載請注明作者)
SMBIOS (System Management BIOS, SMBIOS),它是一種定出主機板及系統廠商如何以標準的格式顯示產品管理資訊的規格。SMBIOS 及 DMI(Desktop Management Interface)規格兩者皆是由 Desktop Management Task Force (DMTF) 所草擬的,它是一個由業界所領導,實行技術規格以確認開放性標準的組織。
對於符合SMBIOS規範的電腦,可以通過訪問SMBIOS的結構獲得系統訊息,共有兩種辦法可以訪問:
1.通過即插即用功能接口訪問SMBIOS結構,這個在SMBIOS2.0標准裏定義了,從SMBIOS2.1開始這個訪問方法不再被推薦使用。
2.基於表結構的方法,表内容是tableentry point的數據,這個訪問方法從SMBIOS2.1以後開始被使用,從2.1開始,以後的版本都推薦使用這種訪問方式。在2.1版本中允許支援這兩種方法中的任意一種和兩種都支援,但在2.2已經以後的版本,必須支援方法2。
鑒於市場上計算機已經均支援SMBIOS2.3標准,所以只考慮方法2,基於表結構的訪問方式。
基於表結構訪問SMBIOS的過程是先找到EntryPoint Structure(EPS)表,然後通過EntryPoint Structure(EPS)表的數據找到SMBIOS數據表。
訪問SMBIOSEPS表的操作過程如下:
1.從物理内存0xF0000-0xFFFFF間尋找關鍵字“_SM_”
2.找到後再向後16個字節,看後面5個BYTE是否是關鍵字“_DMI_”,如果是,EPS表即找到。
注:按照SMBIOS規範説明,找到關鍵字”_SM_”後就可以確定此處就是EPS表結構,但我在實際操作中發現有為數不少的電腦的指定64K内存中有不只一個“_SM_”,所以不能只用找到”_SM_”來確定,需要繼續判斷16個字節後是否是“_DMI_”。
SMBIOSEPS表結構如下:
位置 名稱 長度 描述
00H 關鍵字 4 byte 固定是“_SM_”
04H Check Sum 1 byte 用於檢查數據
05H 表結構長度 1 byte Entry Point Structure表的長度
06H Major版本號碼 1 byte 用於判斷SMBIOS版本
07H Minor版本號碼 1 byte 用於判斷SMBIOS版本
08H 表結構大小 2 byte 用於即插即用接口方法獲得數據表結構長度
0AH EPS修正 1 byte
0B-0FH 格式區域 5 byte 存放解釋EPS修正的訊息
10H 關鍵字 5 byte 固定為“_DMI_”
15H Check Sum 1 byte Intermediate Entry Point Structure(IEPS)的Check Sum
16H 數據表長度 2 byte SMBIOS數據表長度
18H 數據表位址 4 byte SMBIOS數據表的真實內存位置
1CH 數據表結構數目 2 byte SMBIOS數據表的結構數目
1EH SMBIOS BCD修正 1 byte
通過EPS表結構中的12H以及14H處(這裡說ㄉ應該是16h及18h,但我還是將原文呈現比較好),得出數據表長度和數據表地址,即可通過地址訪問結構表。從EPS表中的1CH處可得知結構表結構的總數,其中TYPE0結構就是BIOSinformation,TYPE1結構就是SYSTEMInformation。
每個結構的頭部是相同的,格式如下:
位置 名稱 長度 描述
00H Type number 1 byte 結構的type number
01H 長度 1 byte 本結的長度,就此type number的結構而言
02H Handle 2 byte 用於獲得SMBIOS結構,使用方法未知
每個結構都分為格式區域和字符串區域,格式區域就是一些本結構的信息,字符串區域是緊隨在格式區域後的一個區域。結構01H處標識的結構長度僅是格式區域的長度,字符串區域的長度是不固定的。
下面以TYPE0(BIOSinformation)為例説明格式區域和字符串區域的關系

TYPE0(BIOSinformation)格式區域如下:
位置 名稱 長度 描述
00H Type number 1 byte 結構的type number,此處是0
01H 長度 1 byte Type 0格式區域的長度,一般為14H,也有13H
02H Handle 2 byte 一般為0000H
04H BIOS廠商訊息 1 byte 此處是BIOS賣方的訊息,可能是OEM廠商名,一般為01H,代表緊隨格式區域後的字串區域的第一個字串
05H BIOS版本 1 byte BIOS版本號,一般為02H,代表字串區域的第二個字串
06H BIOS開始位址段 2 byte 用於計算常駐BIOS鏡像大小的計算,方法為(10000H-BIOS開始位址段)*16
08H BIOS發佈日期 1 byte 一般為04H,表示字串區第三個字串
09H BIOS ROM Size 1 byte 計算方法為(n+1)*64K,n為此處讀出的數值
0AH BIOS特徵 8 byte BIOS的功能支援特徵,如PCI,PCMCIA,FLASH等等
12H BIOS特徵擴展 不定
緊隨TYPE0(BIOSinformation)結構區域之後的就是TYPE0(BIOSinformation)字符串區域,如下所示:
db‘System BIOS Vendor Name’,0 ; 字符串以零結尾,第一個字符串:賣方訊息
db‘4.04’,0 ; 第二個:BIOS版本
db‘00/00/0000’,0 ; 第三個:發布日期
db0 ; 以0為整個字符區域的結尾,所以要找下一個TYPE,只要在字符區域找到連續的0000H即可
注:當有EPS表中得到結構表的開始地址後,可以直接按結構來尋找相應的TYPE號,找到後直接讀取就是該TYPE對應的結構的格式區域訊息,然後向後移動結構區域長度(結構區域長度由該結構的01H處讀出)個BYTE,即是該TYPE機構的字符串區域。
由上面介紹可知,獲得BIOS訊息的辦法就是:
1.通過EPS表的12H和14H數據找到TYPE結構表,然後找到TYPE0的内存地址。(不一定是首個)
2.由TYPE0結構區域中得出相應BIOS訊息是否存在(存在則是上面所述的 01H,02H,03H依次排布,不存在則是相應的位置上為00H)。
3.如存在訊息,則從字符串區域中讀取對應BIOS訊息。
獲得SYSTEM信息方法同上,只是TYPE結構區域有所不同,請參照SMBIOSReference Specification

在Linux環境裏可以使用dmidecode這支程式去dump SMBIOS的資料
dmidecode主要功能:
桌面管理介面提供標準化的電腦硬體描述,包括硬體的特性,比如 BIOS 的序號、與硬體連接線。dmidecode 提供由 BIOS 輸出 DMI 的資料,通常被其他硬體偵測程式當作後端工具使用。
轉載來源:
http://cupidsd.bokee.com/4052760.html\
其它參考資料:
System Management BIOS (SMBIOS) Specification
Desktop Management Interface (DMI) Standards
一篇世新的碩論-SMBIOS的研究與實作 寫得算蠻完整的唷
CodeGuru SMBIOS Demystified Windows VC++6.0
張貼者: 史丹利 位於 下午 9:05
--> 閱讀更多...

2009年4月9日 星期四

●有關32位元作業系統記憶體4G位址空間的局限

這篇文章網路有很多,但是對玩記憶體的我來說,卻不可不知。
有關32位元作業系統記憶體4G位址空間的局限:
4GB位址空間的局限:
首先我們還必須要先瞭解兩個概念
其一是“實體記憶體”。大家常說的實體記憶體就是指安裝在主板上的記憶體條,其實不然,在電腦的系統中,實體記憶體不僅包括裝在主板上的記憶體條(RAM),還應該包括主板BIOS晶片的ROM,顯卡上的顯存(RAM)和BIOS(ROM),以及各種PCI、PCI-E設備上的RAM和ROM。
其二是“位址空間”。位址空間就是對實體記憶體編碼(位址編碼)的範圍。
所謂編碼就是對每一個物理存儲單元(一個位元組)分配一個唯一的位址號 碼,這個過程又叫做“編址”或者“位址映射”。這個過程就好像在日常生活中我們給每家每戶分配一個位址門牌號。與編碼相對應的是“定址”過程——分配一個 位址號碼給一個存儲單元的目的是為了便於找到它,完成資料的讀寫,這就是“定址”,因此位址空間有時候又被稱作“定址空間”。系統不僅要給主板上的記憶體條 編址,還要給上述的其他實體記憶體編址;它們都被編在同一個位址空間內,編址後的實體記憶體就可以被系統資源使用或佔用。
從Pentium Pro處理器開始,CPU的 位址匯流排已經升級到36位元,定址能力達到64GB,按理說CPU支援4GB的記憶體是沒有問題的;因此,晶片組(北橋—MCH)位址匯流排的數量就成了決定物 理記憶體位址空間大小的決定性因素。在Intel 945系列和945以前的晶片組,nForce 550系列和550以前的晶片組都只有32條位址線,為系統提供4GB的位址空間,即最高可以安裝4GB的記憶體條。
雖然可以安裝4GB記憶體條,但這4GB的記憶體空間不能全部紛配給記憶體,因為從4GB空間的頂端位址(FFFF_FFFFh)開始向下要有400MB-1GB的位址空間要分配給主板上的其他實體記憶體。

我們可以看到4GB的位址空間可以分為兩大部分,0MB~實體記憶體頂端 的地址分配給主板上安裝的實體記憶體,4GB到實體記憶體頂端的位址分配給BIOS(ROM)和PCI/PCI-E設備的記憶體。由於這些記憶體基本上是用於 系統的輸入和輸出,所以Intel又把這段位址空間稱之為“MMIO”(Memory-Mapped I/O—I/O記憶體映射)。當系統安裝3GB以下的記憶體時,MMIO區域不會與實體記憶體條的位址空間相重疊,作業系統可以訪問幾乎全部的實體記憶體,而操 作系統屬性裏顯示的實體記憶體基本接近實際記憶體的容量。
而當系統安裝上4GB記憶體時,問題出現了。由於位於4GB下面的部分位址空間要優先分配給MMIO,記憶體條上對應的這段區間就得不到編址,所以作業系統就不能使用。
嚴格意義上來說,即使安裝2GB記憶體時作業系統也不可能使用到全部的內 存容量,諸如傳統DOS的UMA區就有部分被佔用的位址空間,但因為被佔用的容量相比之下實在太少,所以就被很多讀者忽略了。MMIO佔用的位址空間在 256MB~1GB之間,這麼大的“浪費”大家肯定不能“熟視無睹”。
因為受4GB晶片組位址空間的限制(32條位址線的限制),Intel 945系列及以前的晶片組、NVIDIA nForce 550及以前的晶片組都沒有辦法繞過這個限制。具體原因有三方面:其一是晶片組沒有剩餘空間分配來供作業系統來調配;其二是實體記憶體的編址必須是連續的, 不能被割斷;其三是系統開機時必需先從4GB的頂端位址(FFFF_FFFFh)讀取BIOS資料, 這是IA32架構和4GB位址空間的局限.
所以建議使用這些晶片組主板的用戶不要安裝4GB的記憶體,這樣會有部分記憶體容量不能被作業系統所使用。而解決4GB記憶體限制的唯一辦法就是擴展位址空間。

二、支援大於4GB記憶體的晶片組和“記憶體重映射”技術
面對原有晶片組4GB記憶體的局限,Intel和NVIDIA早就開始未雨綢繆,他們對傳統的32位元位址匯流排進行了 調整,將其升級到36位,並推出了一系列可以突破4GB記憶體限制的晶片組,這就是Intel的965系列以及975系列、NVIDIA的nForce 570/590以及680系列

注:AMD的64位元Socket AM2 CPU把記憶體控制器放到CPU中,提供40bit的物理位址匯流排,位址空間可達到1000GB。具體支援的位址空間和記憶體量取決於晶片組及主板的匯流排設計。
從上面的晶片組參數來看,位址匯流排從32位元提升到36位,位址空間達到 64GB,支持安裝8GB的實體記憶體。但由於IA32架構的規則是開機時必須從4GB的FFFF_FFFFh位址讀取BIOS資訊,儘管晶片組支援的位址 空間變大了,且最大支援的實體記憶體容量也達到了8GB(或以上),但從本質上來說仍然不能解決MMIO位址佔用4GB記憶體編址的問題。這要怎麼辦呢?
36位元位址匯流排最大可以支援64GB的位址空間,這就為移動MMIO地 址區提供了條件。現在解決這個問題的辦法就是“記憶體重映射”技術——就是在IA32架構的基礎上,把BIOS(ROM)和PCI/PCI-E設備佔用的 MMIO位址區段重新映射到記憶體條頂端位址以上 (例如4GB以上)的位址空間,從而把IA32架構規定的這一段作業系統不可使用的、位於4GB下面的MMIO位址空間回收給實體記憶體使用,保證實體記憶體 編址的連續性。

三、BIOS必須支援“記憶體重映射”
“記憶體重映射”技術必須通過BIOS完成。所以BIOS必須具有支援記憶體重映射的功能模組,以便根據用戶安裝的 記憶體容量來確定是否需要啟用記憶體重映射功能。同時,在BIOS的設置選單中也要有“Memory Re-Mapping”的設置選項,使用4GB或者4GB以上記憶體的用戶一定要將此項設置設為“Enable”。

四、解決4GB記憶體問題還需要作業系統支援
我們常使用的桌面作業系統是32位元的,支援4GB的位址空間。前面我們介紹了解決4GB問題的晶片組是支持 64GB位址空間的,在這樣的晶片組主板上安裝32位元的作業系統,就只能使用4GB的位址空間,因此安裝4GB記憶體不能使用僅支援4GB位址空間的32位元 的作業系統。應該使用支援大於4GB位址空間的32位元作業系統或64位元的作業系統。

五、小結.
1、由於iA32架構要求BIOS(ROM)晶片的位址, PCI、PCI-E記憶體位址、APCI中斷路由位址等必須佔用從4GB開始以下的256M-1GB空間。這段MMIO位址區不能分配給記憶體條。4GB的記憶體條有256MB-1GB的容量不能編址而浪費。
2、使用4GB或者以上的記憶體條,必須使用位址(編址)空間64GB的晶片組主板。
3、記憶體重映射就是把被MMIO佔用的位址移到記憶體條容量以上的位址空間。)
4、BIOS應具有支援“記憶體重映射”功能,設置項裏有 Memory Remap Feature 選項,並設置為Enable。
5、必須安裝定址空間大於4GB的作業系統。比如Windows 2000高級伺服器版,以及64位元作業系統。
6、所有位址空間為4GB的晶片組(Intel945和nForce550之前的),和32位元作業系統均不能利用“記憶體重映射”技術解決4GB記憶體問題。

跟這有關ㄉ討論還有這ㄍ連結。
--> 閱讀更多...

2009年3月30日 星期一

●分解BIOS

注意:本網站討論的部分內容不詳,還沒瞭解透,定義為:不清昕,可能有錯誤的。

這裡主要以Intel平臺的BIOS檔討論,輔助參考AMD平臺的BIOS文件。要分解的BIOS檔選了當下較新的X38晶片組平臺的ex38dq6.f2 這個BIOS檔,而BIOS的檔是ma79xds4.f4,這是AMD的最新的7系晶片組其中的790X晶片組平臺。好,下面開始進行分解ex38dq6.f2這個BIOS檔。

一、工具的使用
1、Ex38dq6.f2是Award Bios,有一個圖形化的BIOS編輯軟體awdbedit,可以很方便的將BIOS的元件分解出來。
2、通用的BIOS編輯軟體cbrom,這裡使用的是cbrom182版本。下面是使用cbrom182顯示BIOS元件的清單,命令列下使用:Cbrom182 ex38dq6.f2 /D,結果如下(部分):

******** ex38dq6.f2 BIOS component ********
No. Item-Name Original-Size Compressed-Size Original-File-Name
================================================================================
0. System BIOS 20000h(128.00K)15478h(85.12K)ex38dq6.BIN
1. XGROUP CODE 0FC40h(63.06K)0B0ECh(44.23K)awardext.rom
2. ACPI table 04E16h(19.52K)0193Ch(6.31K)ACPITBL.BIN
3. EPA LOGO 0168Ch(5.64K)0030Dh(0.76K)AwardBmp.bmp
4. GROUP ROM[18] 031D0h(12.45K)0225Ah(8.59K)ggroup.bin
5. YGROUP ROM 0C180h(48.38K)066E4h(25.72K)awardeyt.rom
6. GROUP ROM[ 0] 08210h(32.52K)0303Dh(12.06K)_EN_CODE.BIN
7. PCI ROM[A] 10000h(64.00K)09DBEh(39.44K)ICH9RAID.BIN
8. PCI ROM 03600h(13.50K)02553h(9.33K)ICH8AHCI.BIN
9. PCI ROM[C] 07A00h(30.50K)04479h(17.12K)JMB59.BIN
10. MINIT 08220h(32.53K)0824Fh(32.58K)DDR2_MRC.X38
11. PCI ROM[D] 0C800h(50.00K)079FDh(30.50K)rtegrom.lom
12. LOGO1 ROM 00B64h(2.85K)00520h(1.28K)dbios.bmp
13. LOGO BitMap 4B30Ch(300.76K)07EEEh(31.73K)x48dq6.bmp
14. GV3 01EFDh(7.75K)00B66h(2.85K)PPMINIT.ROM
15. OEM0 CODE 028ABh(10.17K)01E1Bh(7.53K)SBF.BIN
(SP) NCPUCODE 1D000h(116.00K)1D000h(116.00K)NCPUCODE.BIN

Total compress code space = E5000h(916.00K)
Total compressed code size = 75C8Dh(471.14K)
Remain compress code space = 6F373h(444.86K)

清單: 2.1

整個ex38dq6.f2 檔1M大小,包含了16個元件,最後的NCPUCODE.BIN元件,是虛擬的或者說物理上不存在,用awdbedit軟體分解不包括這個元件,實際上只有15個真實元件,這些元件全都是經過壓縮的。第2列是元件的名字,第3列是元件真實的大小,第4列是元件中部分壓縮的資料在ex38dq6.f2檔中的大小,最後1列是分解後元件存在磁片上的物理檔案名,以ex38dq6.bin為例,這個元件真實的大小為128K,其中85.12K是壓縮部分,其餘的以純代碼形式分佈在FE000 ~ FFFFF區域,典型地:第一條far jmp就分佈在這個區域。
ex38dq6.BIN 是BIOS的主體組件。
awardext.rom、awardeyt.rom 是BIOS的擴展部分。
ACPITBL.BIN 是供ACPI所使用的低級部件,可供作業系統使用。
PCI ROM 是 PCI 設備的一些元件。
還有一些顯示的BMP圖片
其餘組件不詳,有待瞭解
3、使用cbrom182來分解元件的方法:
Cbrom182 ex38dq6.f2 /XGROUP extract 分解出 awardext.rom
Cbrom182 ex38dq6.f2 /ACPI extract 分解出 ACPITBL.BIN
如此類推,可以逐步分解出各個元件,但是,SYSTEM BIOS元件,也即是 ex38dq6.bin 這個元件,我怎麼試也沒分解出來,所以用以下推薦的方法分解。

4、推薦分解BIOS元件的方法
使用圖形化的BIOS編輯軟體awdbedit可以很方便簡單分解全部的元件。運行awdbedit軟體,打開ex38dq6.f2,忽略掉一些警告資訊,進入後,選擇 [Actions] –> [Extract All] 就可以分解出全部的元件。

二、BIOS元件位置分析
1、ex38dq6.f2檔共1M大小,除了包含各個BIOS元件外,還充斥著大量的“填充碼”,這些“填充碼”是FF位元組以及00位元組,主要用來分隔各個元件,以及填充檔。
2、壓縮元件是以LZH形式壓縮,每個壓縮元件以“-lh5-”開頭,十六進位碼形式為 2D 6C 68 35 2D,這是壓縮組件的戳記,因此,在BIOS檔中只要尋找到這個戳記就可以區分開每個元件。
seg000:0000 24 F7 2D 6C 68 35 2D 50 54 01 00 00 00 02 00 00 $?lh5-PT ... ..
seg000:0010 00 00 50 20 01 0B 65 78 33 38 64 71 36 2E 42 49 ..P
ex38dq6.BI
seg000:0020 4E 24 D3 20 00 00 2D 20 8F 77 BF 74 89 29 BB AA N$?..- 弚縯?華
seg000:0030 7F 33 33 37 37 4D 07 73 55 45 55 78 35 91 D5 66 3377MsUEUx5懻f
seg000:0040 85 B7 54 49 34 52 21 0E 9B A5 10 91 11 BC 1D 28 叿TI4R!
洢 ??(
seg000:0050 B1 2A 66 A0 DD 5B BB BA 9C 0D 51 0C C5 17 AA F2 ?f犦[緩?Q
?
seg000:0060 FB DD BC AC AD 34 F1 55 DB 53 CC 03 DD A6 86 30 棘?馯跾?葒?
seg000:0070 2A CF 42 B5 DC 53 52 22 43 F0 75 84 66 40 00 77 *螧弟SR"C饀刦@.w
seg000:0080 7F FE 66 83 37 77 79 E7 9E BC F6 FF BD 7A FD EE �?wy鐬薦�絲
seg000:0090 BE FF 04 3E F7 76 B2 49 1B 6D C9 D1 4B 2D 15 A0 ? >鱲睮 m裳K- ?
seg000:00A0 AE 84 C4 52 58 5F FF CF ED 24 AC C1 42 64 1F F0 畡腞X_�享$Bd­?
seg000:00B0 BF 45 55 49 0A A2 CE C2 97 58 58 AF 0E 62 22 84 縀UI⑽聴XX?b"?
seg000:00C0 7E CF 94 2F E7 24 F7 E3 CE 0F 55 B8 E0 94 E0 D5 ~蠑/?縻?U膏斷?
seg000:00D0 D1 BE E0 9E FB 99 C1 F8 3B 86 C5 B8 86 6C 6B 85 丫酁麢柳;喤竼lk?
seg000:00E0 88 B3 F7 05 5A F0 BA CB C3 2E 5F 89 F8 AF ED B2 埑?Z鷙嗣._夬?
seg000:00F0 91 9C 42 50 B7 CA 60 34 B6 4A 55 8C 65 D3 8E EA 憸BP肥`4禞U宔訋?
seg000:0100 6A 5D E1 4F 7E DB 97 7F 4C A0 AE 9E 15 B7 8E 86 j]酧~蹢L牣?穾?

清單 2.2

3、以ex38dq6.f2為例,用十六制編輯軟打開,從00000000開始到000FFFFF共1M的大小,每個壓縮元件在ex38dq6.f2的物理位置如下:
0. 0 ~ 15477: System Bios (ex38dq6.bin)
1.15478 ~ 20563: XGROUP CODE(awardext.rom)
2.20564 ~ 21E9F: ACPI table(ACPITBL.BIN)
3. 21EA0 ~ 221AC: EPA LOGO(awardBmp.bmp)
4.221AD ~ 24406: GROUP ROM[18](ggroup.bin)
5.24407 ~ 2AAEA: YGROUP ROM(awardeyt.rom)
6.2AAEB ~ 2DB27: GROUP ROM[0](_EN_CODE.BIN)
7.2DB28 ~ 378E5: PCI ROM[A](ICH9RAID.BIN)
8.378E6 ~ 39E38: PCI ROM(ICH8AHCI.BIN)
9.10. 39E39 ~ 46500: PCI ROM[C]、MINIT(JMB59.BIN、DDR2_MRC.X38)
11.46501 ~ 4DEFD: PCI ROM[D](rtegrom.lom)
12.4DEFE ~ 4E41D: LOGO1 ROM(dbios.bmp)
13.4E41E ~ 5630B: LOGO BIGMAP(X48DQ6.bmp)
14.5630C ~ 56E71: GV3(PPMINIT.ROM)
15.56872 ~ 58C8C: OME0 CODE(SBF.BIN)

以上是各個壓縮元件在BIOS檔中的物理位置,從58C8D ~ FDFFF 這段區間中混合著一些資料,還在大量充斥著“填充碼”,沒有什麼實際的意義,或者說:沒看到什麼實際意義。從 FE000 ~ FFFFF 這段區間中,包含一些非壓縮的純二進位碼,其中有重要的BOOTBLOCK,以及一些初始化代碼。也包含著大量的“填充碼”。這些純代碼分散分佈在這個區間,純代碼與部分壓縮元件的混合在一起,幾乎很難區分哪些是純代碼,哪些是壓縮資料,指令:jmp far ptr 0F000:0E05B 與其它資料混合在一起,如下清單2.2所示:
seg000:FFB25 db 0C3h ; ?
seg000:FFB26 db 66h ; f
seg000:FFB27 db 0EFh ; ?
seg000:FFB28 db 8Bh ; ?
seg000:FFB29 db 0D7h ; ?
seg000:FFB2A db 8Eh ; ?
seg000:FFB2B db 0D9h ; ?
seg000:FFB2C ; ---------------------------------------------------------------------------
seg000:FFB2C jmp far ptr 0F000h:0E05Bh
seg000:FFB2C ; ---------------------------------------------------------------------------
seg000:FFB31 db 0
seg000:FFB32 db 0
seg000:FFB33 db 0
seg000:FFB34 db 0
seg000:FFB35 db 0
seg000:FFB36 db 0
seg000:FFB37 db 0
seg000:FFB38 db 0
seg000:FFB39 db 0

清單 2.3

4、BIOS的主體文件 ex38dq6.BIN的大小是128K,正好映射到系統位址空間的FFFE_0000 ~ FFFF_FFFF(E_0000 ~ F_FFFF)共128K的空間上。
當分解出BIOS主體元件ex38dq6.BIN後,這條指令就在F000:FFF0 的位置上,如下清單2.3所示:

seg000:FFFEC db 80h ; €
seg000:FFFED db 1
seg000:FFFEE db 0Ch
seg000:FFFEF db 89h ; ?
seg000:FFFF0 ; ---------------------------------------------------------------------------
seg000:FFFF0 jmp far ptr 0F000h:0E05Bh
seg000:FFFF0 ; ---------------------------------------------------------------------------
seg000:FFFF5 db 30h ; 0
seg000:FFFF6 db 32h ; 2
seg000:FFFF7 db 2Fh ; /
seg000:FFFF8 db 32h ; 2
seg000:FFFF9 db 37h ; 7
seg000:FFFFA db 2Fh ; /
seg000:FFFFB db 30h ; 0
seg000:FFFFC db 38h ; 8
seg000:FFFFD db 0
seg000:FFFFE db 0FCh ; ?
seg000:FFFFF db 0B3h ; ?
seg000:FFFFF seg000 ends

清單 2.4

在ex38dq6.BIN 檔中的FFFF0位置對應著物理FFFFFFF0這個位址上,第1條指令是far jmp,跳轉到BOOTBLOCK中,通常在這條指令的周圍是些有意議的字元描述,如:02/27/08這是BIOS日期,在far jmp 下麵處於BIOS尾端。

三、不同BIOS檔之間的異同

1、結構不同,AMI和award的BIOS是有差別的。
2、BIOS檔的大小不同,一般的BIOS檔大小為512K,以ma79xds4.f4為例,它是512K,ex38dq6.f2是1M,但結構上差什麼差異,下面是ma79xds4.f4的結構:

No. Item-Name Original-Size Compressed-Size Original-File-Name
================================================================================
0. System BIOS 20000h(128.00K)13944h(78.32K)ma79xds4.BIN
1. XGROUP CODE 0F7D0h(61.95K)0AB7Bh(42.87K)awardext.rom
2. ACPI table 06391h(24.89K)02B35h(10.80K)ACPITBL.BIN
3. EPA LOGO 0168Ch(5.64K)0030Dh(0.76K)AwardBmp.bmp
4. GROUP ROM[18] 03340h(12.81K)02339h(8.81K)ggroup.bin
5. YGROUP ROM 0B310h(44.77K)05023h(20.03K)awardeyt.rom
6. GROUP ROM[ 0] 07100h(28.25K)02C90h(11.14K)_EN_CODE.BIN
7. PCI ROM[A] 0C800h(50.00K)0AC37h(43.05K)sata22.bin
8. OEM1 CODE 0AE4Fh(43.58K)06B6Dh(26.86K)ui22.bin
9. PCI ROM[B] 0A800h(42.00K)06007h(24.01K)RTLGPXE.LOM
10. LOGO1 ROM 00B64h(2.85K)00520h(1.28K)dbios.bmp
11. OEM0 CODE 028ABh(10.17K)01E1Bh(7.53K)SBF.BIN
12. GV3 088C6h(34.19K)026FBh(9.75K)AGESACPU.ROM
13. MINIT 11B80h(70.88K)11BB3h(70.92K)MEMINIT.BIN
14. HTINIT 04BC0h(18.94K)04BF0h(18.98K)HT.DLL
15. 2 PE32 in MB 00552h(1.33K)00582h(1.38K)HT32GATE.BIN
(SP) NCPUCODE 04000h(16.00K)04000h(16.00K)NCPUCODE.BIN

Total compress code space = 63000h(396.00K)
Total compressed code size = 621F3h(392.49K)
Remain compress code space = 00E0Dh(3.51K)

清單 2.5

上面清單所示,與ex38dq6.f2的結構一樣,每個元件都有一部分是經過壓縮的。
--> 閱讀更多...

●跟著流程走(一):far jmp後發生什麼?




跟著流程走(一):far jmp後發生什麼?
一、所需材料
1、主要BIOS :ex38dq6.f2 :技嘉主機板上Intel X38 MCH + ICH9 平臺。
備用BIOS:ma79xds4.f4 : 技嘉主機板上AMD 790X 北橋 + SB600 南橋平臺。
2、cbrom:這是一個BIOS編輯工具,這裡所用的是cbrom182版本
3、lha2.55:LHA格式的解壓工具。
4、awdbedit:award bios 的圖形化編輯工具,方便簡單。
5、hex workshop:一個十六進位編輯工具,簡單小巧。
6、IDA:一個反彙編工具,這裡使用的是IDA 5.2版本

二、所需知識
1、組合語言:這是必備的知識,彙編掌握的程度和理解能力成正比。
2、機器語言:這個不是必需的,但推薦能夠讀懂機器語言,某些場合下當組合語言也陷入窘境時,機器語言是唯一的解釋手段。
3、x86體系知識:具體可以查看相關的Intel 或 AMD 手冊
4、ISA/PCI 匯流排知識:可以查看相應的 ISA/PCI Specification
5、north/south bridge 知識:Intel 現在以MCH代稱north bridge,ICH代稱south bridge,可以查看相應的 datasheet


接下來用IDA pro打開ex38dq6.BIN觀察,這個是BIOS的主體檔,跟著流程走,看看far jmp後BIOS做什麼工作。
1、第一條指令 jmp far ptr F000:E05B 經過幾個跳轉,跳到F000:F46C處
2、以下是F000:F46C的代碼:
seg000:FF46C cli
seg000:FF46D cld
seg000:FF46E xchg bx, bx
seg000:FF470 smsw ax
seg000:FF473 test al, 1
seg000:FF475 jz short near ptr 0F480h
seg000:FF477 cli
seg000:FF478 mov al, 0FEh ; '?
seg000:FF47A out 64h, al ; AT Keyboard controller 8042.
seg000:FF47A ; Resend the last transmission
seg000:FF47C cli
seg000:FF47D hlt
--------------------------------------------------------------
取機器狀態字,也就是CR0寄存器,測試CR0.PE是否為1,判斷CPU是否處於真實模式狀態,若不是則停機。
若處於真實模式轉到F000:F480繼續處理。
3、轉到F000:F480又經過一道跳轉,來到F000:E043進行處理
4、下麵是F000:E043的代碼:

seg000:FE043 mov al, 8Fh ; '? ; disable NMI# and get 0Fh offset register
seg000:FE045 out 70h, al ; CMOS Memory:
seg000:FE045 ;
seg000:FE047 out 0EBh, al
seg000:FE049 in al, 71h ; get OFh offset register data
seg000:FE04B out 0EBh, al
seg000:FE04D or al, al ; is RESET ?
seg000:FE04F jmp near ptr 0F483h

在這裡,取 CMOS RAM 中位於0F處1個位元組的資料,通過測試這個位元組是否為0,判斷是否屬正常啟動。
5、正常啟動的話,調用F000:54DE這個子過程進行處理,否則跳到F000:3468。
二、下面看看F000:54DE的處理,以下是第二張流程圖:
下面proc_F54DE的代碼:

seg000:F54DE mov ax, 0
seg000:F54E1 mov es, ax
seg000:F54E3 cmp word ptr es:472h, 1234h
seg000:F54EA jnz short near ptr 54F8h
seg000:F54EC mov al, 8Fh ; '?
seg000:F54EE out 70h, al ; CMOS Memory:
seg000:F54EE ;
seg000:F54F0 out 0EBh, al
seg000:F54F2 mov al, 0AAh ; '?
seg000:F54F4 out 71h, al ; CMOS Memory:
seg000:F54F4 ;
seg000:F54F6 out 0EBh, al
seg000:F54F8 mov dx, 3C4h
seg000:F54FB mov al, 1
seg000:F54FD out dx, al ; EGA: sequencer address reg
seg000:F54FD ; clocking mode. Data bits:
seg000:F54FD ; 0: 1=8 dots/char; 0=9 dots/char
seg000:F54FD ; 1: CRT bandwidth: 1=low; 0=high
seg000:F54FD ; 2: 1=shift every char; 0=every 2nd char
seg000:F54FD ; 3: dot clock: 1=halved
seg000:F54FE inc dl
seg000:F5500 in al, dx ; EGA port: sequencer data register
seg000:F5501 or al, 20h
seg000:F5503 out dx, al ; EGA port: sequencer data register
seg000:F5504 call near ptr 76FBh
seg000:F5507 retn

1、在BIOS資料區的0472處存放著一個重定標誌:
seg000:F54E3 cmp word ptr es:472h, 1234h
通過比較 [0472] 是否1234h,標誌1234h是一個暖開機標誌位元,機器暖開機時,例如:按下CTRL+ALT+DEL 三個鍵時,由鍵盤中斷處理常式在[0472]處寫標誌1234h。
2、是暖開機的話,將寫入AA標誌到CMOS RAM 的0F處。
3、接著設置EGA相應的工作狀態。
4、在proc_F76FB過程裡置計時器1的狀態。
5、最後調用過程proc_F2941進行晶片組的初始化。

三、下面是本站節的重點,初始化某部分晶片組,下面是流程圖:
1、下面重點理解 write_pci_byte這個BIOS提供的rontine,代碼如下:

seg000:FF798 xchg ax, cx ; write_byte routine
seg000:FF799 shl ecx, 10h
seg000:FF79D xchg ax, cx
seg000:FF79E mov ax, 8000h ; Bus 0
seg000:FF7A1 shl eax, 10h
seg000:FF7A5 mov ax, cx
seg000:FF7A7 and al, 0FCh
seg000:FF7A9 mov dx, 0CF8h ; config_address register
seg000:FF7AC out dx, eax
seg000:FF7AE add dl, 4 ; config_data register
seg000:FF7B1 mov al, cl
seg000:FF7B3 and al, 3
seg000:FF7B5 add dl, al
seg000:FF7B7 mov eax, ecx
seg000:FF7BA shr eax, 10h
seg000:FF7BE out dx, al
seg000:FF7BF retn

將這個routine功能簡化為C代碼形式來看比較直觀:
void wirte_pci_byte(int offset_number, int mask)
{
if (number == -1)
jmp_7666();

do_wirte_pci_byte(offset_number, mask);
}

這段routine固定寫PCI的Bus0,Device0,Function0,offset 值放在cx中,由調用者傳來,置什麼值放在al寄存器,這是1個位元組的值。Bus0,Dev0,Fun0是hostbrige控制器(NorthBridge),也即是DRAM控制器的地址所在。這段代碼是典型的寫PCI設置的手法。PCI設置位址送入config_address_register中,然後往config_data_register裡寫資料,這個PCI設備位址將映射到PCI設備的寄存器,如前面介紹的位址空間圖所示,PCI設備位址範圍是E000_0000 ~ EFFF_FFFF,這段空間提交到相應的PCI設備。
2、現在回過頭來看調用者,cx=95,al=33 這個參數傳給 write_pci_byte。Offset是95,mask碼是33。Offset 95在write_pci_byte將被置為94,這將是DRAM控制器的PAM4寄存器,PAM4寄存器控制D_8000 ~ D_FFFF記憶體空間的屬性。寫入33,結果是:將這段空間置為read/write屬性,這將是所有訪問這段空間的操作會提交到DRAM。而不再是ROM。

3、Offset 96的結果和offset 95一樣,在write_pci_byte的遮罩中被置為offset 94。
--> 閱讀更多...

2009年3月27日 星期五

●有關smm模式及big real mode

有沒有32位真實模式,why?
在80286之後的機器上,在真實模式下已經可以部分使用32位元資料,如寄存器可以用eax等,但根本的問題是不能定址32位的位址空間,但原因不是在真實模式下不能使用32位元的定址方式,而是位址空間被“封閉”了。
如果你寫一段程式,選進入保護模式,將gs,fs等寄存器設置為可以定址全部記憶體空間,然後返回到真實模式,只要你不刷新gs /fs,則始終可以通過它們訪問全部記憶體,這表明在真實模式下是具備32位能力的,只是不太好用罷了。
Q:請問為什麼不太好用啊?A:你要在真實模式和保護模式下頻繁地切換,累啊。
因為一般來說程式中總是需要偶爾改動一下ds,es,cs這些常用的段寄存器,因此在真實模式下,在大多數時候還是受到限制,上面回復的方法只是突破了資料段的限制,使資料段可以達到4G,但程式碼片段還是不行。
intel 的文檔裡說的很清楚。SMM模式特意設計成只能讓系統的固件使用,不能被使用者程式和系統程式進入。進入SMM模式的方法是給SMI#管腳輸入一個電平信號 或者通過APIC給匯流排發一個SMI消息。你在看看smm那章,smm與其他模式切換是比較特殊,但關於big real mode 的介紹也只出現在intel手冊的這章中。smm模式使用真實模式的段式管理,但他的資料段描述符是4g的。
intel cpu smm模式與其他模式的切換只要你有晶片組的手冊就能知道如何切換(處於特權級0),cyrix的cpu 通過寄存器 0x22 0x23也可以切換。

問題越來越有趣了。flat(big) real mod is not system manager mode。SMM的進入方法我想我也沒有理解錯,intel x86進入SMM的唯一方式就是給SMI#引腳輸入信號,具體可以通過對ACPI或者fireware進行程式設計實現。進入SMM方式比進入big real mode要複雜,一方面要對APIC或者fireware程式設計,另一方面要設置好SMM的執行環境。intel文檔中也明確說明SMM方式特意設計成只能 讓fireware執行(當然,系統程式通過APIC也是可以實現的)。
在網上搜集了一些資料是說flat(big) real mode的,在486S後確實存在這種32位的真實模式,其位址是32位元的,但是指令預設是16位元的,如果執行32位元指令要在前面加首碼。一旦進入flat real mode,也沒有必要去更改CS,DS,FS,ES等段寄存器了,因為記憶體是平坦模式,基底位址是00000000,界限是4G,所以可以放心使用,關鍵問 題是16位元指令和32位元指令混合使用會產生麻煩。Windows 3.1就是使用這種模式。但很奇怪,intel的手冊裡面沒有提到過flat(big) real mode,也許正如文中所說,當Pentium引入時,big real mode再也沒有什麼吸引力了,以至於flat real mode只是曇花一現,這種模式成了intel公司的X file.

是的是的,書上說的沒錯,你理解也正確。我最開始的意 思就是big real mode在intel的手冊也只有smm這章有過介紹。big real mode有多中叫法:unreal mode ,falt real mode,其實都是一個意思,在real mode 下使用4g記憶體。不過切換到smm 模式我個人並不覺得有多困難,intel 晶片組的手冊是開放的!切換到smm只要通過晶片組允許0xA0000,然後寫io 埠0xb2產生smi中斷就切換到smm了,退出用rsm指令,smm是個有趣的模式,在這個模式裡你可以看到Descriptor Cache 的內容!

--> 閱讀更多...

2009年3月26日 星期四

●X86開機時的狀況

開機後,CPU重置,從位址FFFFFFF0取第一個命令,這個位址正好落在ROM BIOS中。該位址內容一定是一個JMP指令,系統便跳轉到該JMP指令所指的地方。
1‧而這裡之後我開始不明白了。JMP要跳轉到的位置是在高地址(4G末端)Flash Rom BIOS中還是在低地址(1M末端)的shadow BIOS呢?
2‧位於低地址(1M處)的(BIOS shadow)是從Flash BIOS拷貝而來呢,還是沒有任何拷貝過程僅僅利用位址映射到原Flash BIOS中的呢?
3‧無論是拷貝還是映射,記憶體位址空間上ROM BIOS映射區只有 0xF0000~0x100000之間的64KB。而ROM本身有可能大於2M。那映射的應該是原BIOS程式的一部分,那麼是哪一部分呢?對這個問題的回答需要闡明機關概念:
1.機器加電時,記憶體控制器還沒有初時化,記憶體是不可用。
2.機器加電時,對CPU的指令的解碼不是北橋,CPU發出的位址被傳遞到南橋並由FHW(Firmware Hub)解碼到BIOS ROM晶片(Flash)。在加電時一直到引導進程初,BIOS的E段(0xE0000~0xEFFFF)和F段(0xF0000~0xFFFFF)和4G記憶體頂端的對應段0xFFFE0000~0xFFFEFFFF和0xFFFF0000~0xFFFFFFFF都被FWH解碼到BIOS的ROM晶片的兩個64區域。即在啟動階段訪問0xE0000~0xEFFFF和0xFFFE0000~0xFFFEFFFF是同一個BIOS區域,訪問0xF0000~0xFFFFF和0xFFFF0000~0xFFFFFFFF是同一個BIOS區域。
3.機器加電時,CS段寄存器值為0xF000,EIP值為0x0000FFF0,但CPU的取的位址是段寄存器不可見的部分(影子寄存器)加上偏移部分,此時影子寄存器的值為0xFFFFFFF0。所以CPU執行的第一條指令是0xFFFFFFF0(復位向量),通常在BIOS ROM對應的指令是一個跳轉指令JMP F000:E05B,當取出跳轉完成後,由於CS段的影子寄存器刷新並重新載入,下一條指令位址是0xFE05B。不過這條指令仍然從BIOS ROM裡取得。
4.關於shadow BIOS,BIOS程式通常是壓縮的,在系統初始化階段,BIOS會解壓BIOS Image到RAM中,然後程式設計北橋控制器對0xE0000~0xFFFFF置為write only,這樣對該區域的寫被傳遞到DRAM裡,然後把解壓的BIOS拷貝到E段和F段。最後重新程式設計北橋控制器對0xE0000~0xFFFFF置為read only。對於PCI ROM BIOS,BIOS會把每個卡上的ROM拷貝到0xC0000~0xDFFFF然後執行他們的初時化代碼。5.BIOS ROM可以很大,但不都是可執行的,如含有ACPI Table等,開始解壓到0xE0000~0xFFFFF只是其中一部分,在啟動過程中還需要從BIOS ROM解壓代碼到RAM中,並覆蓋其中不需要的代碼。這個就好像BIOS ROM是硬碟(不過可用直接訪問),真正執行的代碼在RAM中一樣。硬碟可以很大但RAM小,這也就是程式的局部性原理。
這個網址也是相關議題的論述:X86 開機流程小記,BIOS 探索之旅可以比較一下是否有差異點。

BIOS的幾個模組中有部分是壓縮的,有部分是 pure binary,純代碼和壓縮代部參雜在一起。
BIOS有部分是 routine 元件,它是 pure binary,其它就包括初始化(晶片組、DRAM等)模式,解壓routine元件、還有就是CPU 的微代碼update模式等等,提供BIOS運行期間的一些函式呼叫,解壓rontine的作用就是解壓壓縮組件,將它們放入相應的memory中。還有 一件重要的事情是,建立一個 interrupter vector 及 interrupt service routine。

bios啟動ram記憶體初始化前bios是否在rom中運行,這樣的話rom的地址會不會跟ram地址衝突?
北橋晶片有 Shadow RAM 功能,ROM 和 RAM 都會映射到同一段位址,但是根據讀寫信號的不同轉到 ROM 或者 RAM去。
第一條 long jmp 指令,也就成為 x86 pc 機的固有約定或者說是規範吧。

其實主要的原因是相容!追溯到最早 808X 系列處理器,8080 是 16 位 address bus, 8086 及 8088 改進為 20 進 address bus,整個 808X 系列處理就是整個 x86 架構的始祖。定址空間 00000 ~ FFFFFh 也就是 1M 的空間。
當時 IBM 決定使用 8086 處理作為 IBM PC 機,故事就從那裡開始,BIOS 這個名詞也就是 IBM 發明出來的,IBM 搞出來的 BIOS 定位在 8086 處理器的定址高端,也就是 F0000 到 FFFFF 區域。從 386 開始,address bus 增加到 32 條,定址範圍從 0 ~ FFFFFFFFh,BIOS 的定位也在 4G 的高端FFFF0000 ~ FFFFFFFFh,但為了相容,對 F0000 ~ FFFFF 的訪問被映射到 FFFF0000 ~ FFFFFFFFh,這是從理論上定義的。
從物理上來講,F0000 ~ FFFFFh 映射到 FFFF0000 ~ FFFFFFFFh 靠硬體來保證,在位址解碼時,F0000 ~ FFFFFh 與 FFFF0000 ~ FFFFFFFFh 會被解碼到同一個區域。現在的晶片組提供的廠商有很多,如:Intel,AMD,nvidia,VIA,SIS 等,它們的解碼實現方法可能會不同,但都要保證這個所謂的“別名”機制。
Intel 實現是:MCH 將 C_0000 ~ F_FFFF 這段區域定義為 PAM(Programed attribute memory),分 disable,read-only ,wirte-only,read/write 四種屬性,初始屬性是 disable,也即是無用,因此這段區域將被送去 ICH 解碼,FFE0_0000 ~ FFFF_FFFFh 的也被 ICH 解碼,ICH 轉交 LPC bridge 處理,它們被解碼為同一區域。
AMD 實現是:無論是 C_0000 ~ F_FFFF,還是 FFFC_0000 ~ FFFF_FFFF 最終結果都將送到 LPC bus 上的 FFFC_0000 ~ FFFF_FFFF 物理位址上。其它的廠商實現也大體這樣。

因此:long jmp 後,轉到 FE05B(jmp far ptr F000:E05B)執行,它將被映射到物理位址 FFFFE05B 上,這還是 BIOS 所在的 ROM 中。第一條指令的 FFFFFFF0 與 第二條的 FE05B 都是在 BIOS 的 ROM 上。
--> 閱讀更多...