2009年3月19日 星期四

●桌面圖示陰影(背景)








這ㄍ問題解法相當簡單:




--> 閱讀更多...

●memtest86+教學 Part2


mt86+_loader.asm這ㄍ檔案就是我上一篇文章賣的關子,有ㄌ它你可以將memtest86+製作成在Dos底下run的執行檔:
exeh: db "MZ"
dw fullsize % 512 ; how much to load from
dw (fullsize + 511) / 512 ; .exe to RAM
dw 0 ; no relocations used
dw 2 ; header size is 2 * 16 bytes
dw stackpara ; minimum heap is 128 * 16 bytes, for stack
dw stackpara ; we do not need more heap either
dw (fullsize + 15) / 16 ; SS is after file
; segment offsets are relative to PSPseg+10h
; initial DS and ES point to PSPseg, and file
; except headers is loaded to PSPseg+10h.

dw stacksize-4 ; initial SP value
dw 0 ; no checksum
dw 100h ; initial IP
dw -10h ; initial CS relative to PSPseg+10h
dw 0 ; no relocation table, "offset 0 in file"
dw 0 ; this is not an overlay
db "MEMT" ; padding to a multiple of 16 bytes
以上這些資訊是從mt86+_loader.asm截取下來,若你看不明白可以參考這份資訊,其他的看完有問題再說。因為到目前為止都還沒進入主題,所以先進入memtest86+殿堂看看究竟‧‧‧。
註:本文使用版本是memtest86+-2.01;首先看一下上圖有哪些檔案:不好意思好像不是頂清楚。首先我們看我圈選起來的那幾個檔案,先說明main.c吧!不要被檔案名稱給誤導ㄌ,學Cㄉ時候是要你知道main這ㄍroutine而不是檔名,所以這ㄍ檔案根本就不是程式ㄉentry(進入點)所在。
另外三ㄍ副檔名為大寫"S"的檔案bootsect.S、head.S、setup.S才是主角(注意,不要在windows將memtest86+-2.01.tar.gz解壓縮,因為windows不區分檔名大小寫),我並不想針對這三ㄍ檔案涉入太深,否則一樣會廢話一堆,但玩過Linux Kernelㄉ大大們對這三個檔案一定不陌生,網路上也有粉多這方面ㄉ討論,但是這三個檔案到底還是很重要,若你完全看不懂,我想你可能要花一段不算短ㄉ時間將它搞懂,因為你若不懂,則接下來的C語言你會Trace的很吃力,也不踏實,雖然說網路上有針對這三ㄍ檔案ㄉ論述,但畢竟memtest86已經修改過因此我會稍為作說明:
這三個檔案是GAS的語法:你必須自己搞懂GAS(Assembly),但mt86+_loader.asm又是nasm的語法‧‧‧‧這些主題若是我精力過旺,或許以後再另闢文章。
1.bootsect.S:先把自己512Bytes從0x7c00搬移到0x90000,並繼續執行;繼續執行的第一ㄍ動做就是movw %cs, %ax #讓cs值也等於0x9000,接著處理一些磁碟參數問題後將setup.S從1.44mbㄉ磁片讀到0x92000,然後是# we want to load the system (at 0x10000):將整ㄍ程式主體從磁碟讀到0x10000處,這個動作就是call read_it,並從0x90200處開始執行,這ㄍ位址就是setup.Sㄉ啟始處。所以bootsect.S所完成的工作就是將程式從磁碟讀到記憶體後再接著去執行setup.S。
所以若你不作成dos版本ㄉ執行檔,原則上執行ㄉ流程是從bootsect.S開始,但相反ㄉ若作成dos版本ㄉ執行檔則bootsect.S幾乎算是ㄍ廢物,因為mt86+_loader執行完就會跳到setup.S
2.setup.S:這部份就是準備進入保護模式ㄉ一些動作,但它不搞cr0,它用lmsw這ㄍ指令進保護模式,反正道理都一樣,若你有認真去看完setup.S,你會發現它只是單純ㄉ進入保護模式,但這樣ㄉ話也可以在head.S作啊,其實說穿ㄌ它用這ㄍ檔主要是啟用a20位址線,由於這部份方法實作有三個,而它(setup.S)通通作,為什麼?請看我postㄉ文章"Fast A20 和92H,及8042到底是什麼關係";其他(改天再詳述)。
3.head.S:這ㄍ檔案才是最佳男主角‧‧‧待續。
--> 閱讀更多...

●memtest86+教學 Part1


首先廢話一篇:我一直很渴望能從事bios相關行業,因為我確定很多你我不了解的規範specification是如何實作他們最清楚,即使從事那一行沒有在ami或award、phoenix這種外商大公司,一樣可以學習到很多東西。也因此我的學習格外牛步;但憑藉"新聞挖挖哇"的精神,從一套看似不起眼的軟體,一樣可以精進你的專業,學習memtest86+就等於是在學習如何玩弄記憶體,然而這也是跟底層很近的起點,畢竟資訊軟體業說破ㄌ就真的是在玩弄記憶體,只是玩法不同便衍生出不同的技術、演算法‧‧‧‧‧真不好意思,用"玩弄"兩ㄍ字對自己好像也不是很敬業。
言歸正傳,memtest86+及memtest86有什麼不同,memtest86+發行版本是base on memtest86,並作些修正因此release的版本較慢吧!關於作者Memtest86+ is written by Samuel Demeulemeester ,the original author of memtest86 is Chris Brady 。但"+"就是有加入一些東西ㄉ意思。加入ㄌ什麼,先賣ㄍ關子請往下看‧‧
首先你必須具備什麼技能: 1會使用linux(不用很厲害,只要你可以安裝完成linux,其他慢慢來.)2你要會看懂C及Assembly.3對X86架構要了解(這部份要時間ㄉ累積,以及你棄而不捨ㄉ精神,誰叫你我都是門外漢又找不到高高手來做朋友)。我個人是用Microsoft virtual PC或Sun xVM VirtualBox安裝linux,然後掛起samba sever,在windows用source Insight來編輯code,這樣很方便,也是我ㄍ人的習慣,畢竟windows有些好用的tools,但你若是linux高手就當我是在廢話。以上的畫面是我ㄉvirtual PC 啟動ubuntu linux的畫面。
--> 閱讀更多...

●Fast A20 和92H,及8042到底是什麼關係

以下是從DOS编程技术這ㄍ大陸博客寫ㄉ資料放ㄌ上來,它裡面還有介紹一些好東西。您可以慢慢參考、品嘗。
早期的PC,控制鍵盤有一個單獨的單片機8042,現如今這個晶片已經給集成到了其它大片子中,但其功能和使用 方法還是一樣,當PC機剛剛出現A20 Gate的時候,估計實在找不到控制它的地方了,同時為這點小事也不值得增加晶片,於是工程師使用這個8042鍵盤控制器來控制A20 Gate,但A20 Gate真的和鍵盤一點關係也沒有,我們先從軟體的角度簡單介紹一下8042這個晶片。
8042有4個寄存器
• 1個8-bit長的Input buffer;Write-Only;
• 1個8-bit長的Output buffer; Read-Only;
• 1個8-bit長的Status Register;Read-Only;
• 1個8-bit長的Control Register;Read/Write。
有兩個埠位址:60h和64h。
• 讀60h埠,讀output buffer
• 寫60h埠,寫input buffer
• 讀64h埠,讀Status Register
對Control Register的操作相對要複雜一些,首先要向64h埠寫一個命令(20h為讀命令,60h為寫命令),然後根據命令從60h埠讀出Control Register的資料或者向60h埠寫入Control Register的資料(64h埠還可以接受許多其它的命令)。
先來看看Status Register的定義,我們後面要用bit 0和bit 1:
bit meaning
-----------------------------------------------------------------------
0 output register (60h) 中有數據
1 input register (60h/64h) 有數據
2 系統標誌(上電重定後被置為0)
3 data in input register is command (1) or data (0)
4 1=keyboard enabled, 0=keyboard disabled (via switch)
5 1=transmit timeout (data transmit not complete)
6 1=receive timeout (data transmit not complete)
7 1=even parity rec'd, 0=odd parity rec'd (should be odd)
除了這些資源外,8042還有3個內部埠:Input Port、Outport Port和Test Port,這三個埠的操作都是通過向64h發送命令,然後在60h進行讀寫的方式完成,其中本文要操作的A20 Gate被定義在Output Port的bit 1上,所以我們有必要對Outport Port的操作及埠定義做一個說明。
• 讀Output Port
向64h發送0d0h命令,然後從60h讀取Output Port的內容
• 寫Output Port
向64h發送0d1h命令,然後向60h寫入Output Port的資料
另外我們還應該介紹兩個命令:
• 禁止鍵盤操作命令
向64h發送0adh
• 打開鍵盤操作命令
向64h發送0aeh
有了這些命令和知識,我們可以考慮操作A20 Gate了,有關8042晶片更詳細的資料,請參考該晶片的Data Sheet。
如何打開和關閉A20 Gate。
理論上講,我們只要操作8042晶片的輸出埠(64h)的bit 1,就可以控制A20 Gate,但實際上,當你準備向8042的輸入緩衝區裡寫資料時,可能裡面還有其它資料沒有處理,所以,我們要首先禁止鍵盤操作,同時等待資料緩衝區中沒 有資料以後,才能真正地去操作8042打開或者關閉A20 Gate。打開A20 Gate的具體步驟大致如下:
1.關閉中斷;
2.等待8042 Input buffer為空;
3.發送禁止鍵盤操作命令;
4.等待8042 Input buffer為空;
5.發送讀取8042 Output Port命令;
6.等待8042 Output buffer有數據;
7.讀取8042 Output buffer,並保存得到的位元組;
8.等待8042 Input buffer為空;
9.發送Write 8042 Output Port命令到8042 Input buffer;
10.等待8042 Input buffer為空;
11.將從8042 Output Port得到的位元組的第2位置1(或清0),然後寫入8042 Input buffer;
12.等待,直到8042 Input buffer為空為止;
13.發送允許鍵盤操作命令到8042 Input buffer;
14. 打開中斷。
下面是完成打開A20 Gate的代碼:
A20Enable:
cli ;1.關閉中斷
call WaitInbufEmpty ;2.等待8042 Input buffer為空;
mov al, 0adh
mov dx, 64h
out dx, al ;3.發送禁止鍵盤操作命令
call WaitInbufEmpty ;4.等待8042 Input buffer為空;
mov al, 0d0h
mov dx, 64h
out dx, al ;5.發送讀取8042 Output Port命令;
call WaitOutbufFull ;6.等待8042 Output buffer有數據;
mov dx, 60h
in al, dx ;7.讀取8042 Output buffer
push ax ;保存讀取的資料
call WaitInbufEmpty ;8.等待8042 Input buffer為空;
mov al, 0d1h
mov dx, 64h
out dx, al ;9.發送寫 8042 Output Port命令
call WaitInbufEmpty ;10.等待8042 Input buffer為空
pop ax
or al, 02h ;11.將從8042 Output Port得到的位元組的bit 1置1
mov dx, 60h
out dx, al ;寫入Output Port
call WaitInbufEmpty ;12.等待8042 Input buffer為空
mov al, 0aeh
mov dx, 64h
out dx, al ;13.發送允許鍵盤操作命令
sti ;開中斷
ret

WaitInbufEmpty:
mov dx, 64h
in al, dx ;讀取Status Register
test al, 02h
jnz WaitInbufEmpty
ret

WaitOutbufFull:
mov dx, 64h
in al, dx
test al, 01 ;讀取Status Register
jz WaitOutbufFull
ret
後來,由於感覺使用8042控制A20運行太慢了(確實,那麼長的代碼,中間還要若干次的wait),所以後來又出現了所謂的Fast A20,實際上,現在的大多數機器都是Fast A20,Fast A20使用92h埠控制A20,同時BIOS裡提供了一個軟中斷來控制A20:
入口:ah=24h
al=0 關閉A20
1 打開A20
2 讀取A20狀態
int 15h
返回:如果BIOS支援此功能,CF=0,否則CF=1
CF=0時,AX返回當前A20狀態,1=打開,0=關閉
像8042中的Output Port中的定義一樣,92h埠的bit 1控制著A20,為1時打開,為0時關閉,從92h中讀一個byte可以看a20的當前狀態,所以對92h的操作如下:
• 讀A20狀態
mov dx, 92h
in al, dx
如果al的bit 1為1表示a20打開,否則為0
• 打開A20
mov dx, 92h
mov al, 02
out dx, al
• 關閉A20
mov dx, 92h
mov al, 0
out dx, al
特別要注意的是,大家從這篇文章的文字中可能也能感覺到,A20 Gate的設計本身就讓人感覺很彆扭,不是那麼流暢,所以和A20有關的事情就難免也會有相同的感覺,很奇怪的是,上面介紹的三種方法並不是在每台機器上 都適用,所以如果你要做一個商務軟體其中要操作A20,那一定要三種方式聯合使用才比較穩妥,否則會有意想不到的結果,LINUX公開的啟動代碼中就是這 麼做的
在DOS下有時我們會在config.sys中寫上一句:dos=high,這句就會把駐留的DOS放到高端記憶體區域去,怎麼放的呢?關鍵點就是打開 A20,然後把DOS從常設記憶體搬到100000h起始的區域去,並把在常設記憶體中佔用的記憶體釋放掉,當然說起來容易,實際做的時候還有很多細節要處理。
說到DOS=HIGH,就不得不提醒大家另一件事,如果在config.sys中有dos=high這一句,那麼恐怕92h的方法和BIOS的方法都會不 完全靈驗(至於操作8042的方法靈不靈我沒有試),這是DOS做了手腳,因為DOS被放到了高端記憶體中,為了保證DOS能正常運行,它不允許你把A20 給關掉,遇到這種情況不要驚慌,不是我寫得不對,確實是DOS太狡猾了。
還有最後一點要特別注意,92h的bit 0是給機器發重定信號的(8042 Output Port的bit 0也是),所以在向92h寫資料時,千萬不要讓bit 0為1,否則機器會重新啟動,如果你的應用程式需要重新開機機器,這也是方法之一,比jmp 0ffffh:0來的還要乾脆。
在其它我們介紹保護模式的文章中,我們會用到上面提到的打開A20的方法,屆時可能就不會做更多的解釋了。
另外,涉及操作A20的資料其實很少,有些資料我手裡也很缺乏,比如92h除bit 0和bit 1以外的定義是什麼我至今也不知道。

更多參考:Gate A20與保護模式
--> 閱讀更多...