Proper Treatment 正當作法/ blog/ posts/ 免窗升級想板基本輸入輸出系統法門
標籤 Tags:
2008-08-17 19:19

為了讓我的 ThinkPad 風扇安靜一點,最近想要把它的 BIOS 升級到最新的版本。因為我的電腦上沒有裝 Windows,只有裝 Linux,所以除非麻煩地重灌 Windows,否則不能使用 IBM 或聯想發佈的 Windows 版 BIOS 升級程式。

以往在 ThinkPad X20 系列的年代,IBM 除了 Windows 版的升級程式以外,還會發佈一張軟碟開機片。也就是我可以下載一個 1.44MB 的檔案,寫到一張軟碟上用來開機。這張軟碟的內容其實是 IBM 用 DOS 拼湊而成的,開機以後 AUTOEXEC.BAT 會自動執行升級程式。就算沒有 ThinkPad 擴充的軟碟機,或手邊沒有空著不用的軟碟(我最近一次看到軟碟好像是馬蓋先的「醜小鴨」那集吧),也可以用 SYSLINUXMEMDISK,直接從下載檔案裡的虛擬軟碟開機。例如我用 GRUB,在 /boot/grub/menu.lst 裡加上一段

title  MEMDISK
kernel (hd0,5)/lib/syslinux/memdisk
initrd (hd0,7)/ccshan/tmp/floppy.img

即可用 /usr/lib/syslinux/memdisk/home/ccshan/tmp/floppy.img 裡的虛擬軟碟開機,因為 (hd0,5) 是我的 /usr 分割區,而 (hd0,7) 是我的 /home 分割區。就算既不用 GRUB 也不用 Linux,也可以用 PXELINUX 從網路上別台電腦上的虛擬軟碟開機進行升級。

現在時代不同了,ThinkPad X60 系列的 BIOS 已經大得軟碟裝不下了,於是 IBM 發佈的開機片不再是軟碟而是光碟。我沒有光碟機,也不想重灌 Windows,所以希望從虛擬光碟開機進行升級,但是事情沒那麼簡單,因為 MEMDISK 只會模擬磁碟,不會模擬光碟。這是因為從光碟開機的過程比從磁碟複雜,要遵從 El Torito 標準進行。IBM 的這張光碟開機片,除了把新的 BIOS 及其更新程式放在一般的 ISO 9660 檔案系統以外,另含一張虛擬的軟碟開機片。當一位有錢擴充 ThinkPad 的用戶,用燒好的實體光碟開機時,ThinkPad 會從實體光碟上載入虛擬軟碟,執行虛擬軟碟上的 DOS。這份 DOS 的 CONFIG.SYS 與 AUTOEXEC.BAT 得先載入實體光碟機的驅動程式,才能讀到前述的 ISO 9660 檔案系統,以執行實體光碟上的 BIOS 更新程式。

我徹夜試驗,發現可以用實體硬碟代替實體光碟,成功升級了我的 BIOS。基本的想法是,在一個實體硬碟的新分割區裡,結合軟碟上的 DOS 開機程式以及光碟上的 BIOS 升級程式。詳情如下。

首先得在實體硬碟裡造一個分割區,如下例 /dev/sda2。這個分割區不用很大,比 IBM 發佈的光碟檔稍大一點就夠了(約 5MB),不過必須位於實體硬碟的前 1024 個磁柱以內(這是 DOS 的限制,迫使我用 gparted 把原本在硬碟最前面的分割區稍微縮小了一點,幸好那只是我的 /usr/local 分割區而已,不很麻煩),而且必須是初選而非邏輯分割區(迫使我用 sfdisk -d 把一個不常用的初選分割區備份然後暫時刪除,升級完再用 sfdisk -uS -N-O… 小心放回分割表內)。

在分割表裡,這個分割區的型別應設為 6 號(也就是 FAT16 的意思),並且可開機旗標應設為真,因為我們就是要用它開機。但是要把它作成 DOS 的開機分割區,除了新造檔案系統

$ sudo mkdosfs /dev/sda2

以外,還需一番移花接木。我從 IBM 下載的光碟檔名為 7buj25uc.iso,其中內含的虛擬軟碟開機片是從位元組位址 0xA800 (= 43008) 開始的 1.44M (= 1474560) 個位元組。為了方便,我把這部份資料擷取成為另一個檔案 7buj25uc.img

$ dd if=7buj25uc.iso of=7buj25uc.img skip=43008 count=1474560 bs=1

這兩個數字是我邊用 tweak 查看光碟檔、邊參考 El Torito 標準文件找到的。我早知道的話,也可以用 Joachim Selke 寫好的程式直接擷取。

要能從 /dev/sda2 這個分割區開機,必須把 7buj25uc.img 這張軟碟的內容複製進去,但是有兩點需要注意的地方。第一,不只要複製檔案,還要複製檔案系統最開頭的開機磁區,但是不能蓋掉裡面所謂的 BIOS 參數區塊,因為那裡存有分割區大小等資訊。第二,根目錄裡表列的第一個檔案必須是 IBMBIO.COM,第二個必須是 IBMDOS.COM,不然開機磁區裡的程式會找不到。

開機磁區是檔案系統開頭的 512 個位元組,其中 BIOS 參數區塊佔用的是位址 3 到 62 之間的 59 個位元組,所以我把區塊前的 3 個位元組與區塊後的 450 個位元組分別從軟碟複製到分割區裡。

$ sudo dd bs=1 count=3 if=7buj25uc.img of=/dev/sda2
$ sudo dd bs=1 seek=62 skip=62 count=450 if=7buj25uc.img of=/dev/sda2

然後我把軟碟裡的所有檔案都複製到分割區裡,但是先複製 IBMBIO.COMIBMDOS.COM。(以下指令假設已存兩個空目錄 /mnt/pool 以及 /mnt/loop。)

$ sudo mount -t msdos /dev/sda2 /mnt/pool
$ sudo mount -t msdos -o loop 7buj25uc.img /mnt/loop
$ sudo cp /mnt/loop/ibmbio.com /mnt/pool
$ sudo cp /mnt/loop/ibmdos.com /mnt/pool
$ sudo cp -u /mnt/loop/* /mnt/pool
$ sudo umount /mnt/loop

此時查看 /mnt/pool/config.sys/mnt/pool/autoexec.bat 可以了解,這張虛擬開機片在掛上光碟以後會執行光碟上的另一個 COMMAND.COM。所以我在把光碟內容複製到分割區裡的同時,乾脆用光碟上的 COMMAND.COM 取代軟碟上 DOS 的 COMMAND.COM

$ sudo mount -o loop 7buj25uc.iso /mnt/loop
$ sudo cp -i /mnt/loop/* /mnt/pool
cp: overwrite `/mnt/pool/COMMAND.COM'? y
$ sudo umount /mnt/loop

最後,我用文字編輯器修改 /mnt/pool/config.sys,把其中的 A: 統統換成 C:(因為要從硬碟而非軟碟開機),並且拿掉呼叫 COMMAND.COM 那一行後面給的參數。

$ vi /mnt/pool/config.sys
$ sudo umount /mnt/pool

大功告成。重新開機以後,請 GRUB 啟動這個新的分割區

root (hd0,1)
makeactive
chainloader +1

即可進入 IBM 的 BIOS 更新程式。