硬碟定址概說
傳統上一般說來定址的方法有古老的C/H/S (cylinder/head/sector)的方法,也就是說硬碟上的pin 腳位,我們傳進去這三個值,硬碟裡面的晶片會自動幫我們轉換到硬碟上一個區塊(block)上去作讀寫。這是最早的根據硬碟實體(硬碟片數量就是cylinder, 讀寫頭數目head)製作的定址方法,以前ATA只定義24bit (H(8b)S(6b)C(10b)), ATA-2定義28bit (H(4b)S(8b)C(16b)),由於一個硬體讀寫sector傳統上512B,所以ATA的硬碟最多只有8G,ATA-2的硬碟最多只有128G。這限制了硬碟的總大小與使用者對不同廠家硬碟的使用。不同廠家硬碟的C/H/S不同,那就要寫不同的程式控制。所以後來提出LBA (Logical Block Addressing)方法,就是不管了,只要給我一個數目,內部轉換是硬碟廠家自己的事,在ATA-6的規格裡面可以定址到48bit, 就是248 Byte。基本上後來的硬碟都能用LBA了。不同廠家的geometry是不一樣的,也就是同樣是80G的硬碟,但可以由不同的CHS總數來達成,這讓要找到真正的LBA定址困擾,所以CHS與LBA有公式做轉換,而且跟當初定義硬碟的geometry head跟sector有關:
LBA = (c * GH + h) * GS + (s - 1)
例如geometry (255,63,xxx) 的(32, 33, 0)的LBA值,就是(0 * 255 + 32) * 63 + (33 - 1) = 2048,通常這就是linux fdisk所切的第一partition位置。
新的usb drive, SSD等已經沒有CHS了,甚至連sector都有定義4k的讀寫。geometry是由OS 跟driver去跟硬碟詢問得到的,最早在DOS由int 13去問硬碟,所以當用virtual machine時,geometry是由virtual machine回報給OS的。由於現在都用LBA,現在已經沒有真正physical 上的geometry意義,像fdisk還可以自己高興隨便定義 (所以在用fdisk等工具時如果無聊自己去定義geometry,不同的話,根據公式轉出的CHS值也會不同,就是要轉換正確LBA,然後bootloader, OS driver大家都同意就好)。總之現在只是邏輯上計算的值,而唯一可能看到的地方是MBR裡面partition的定義,那個也基本無意義了,我猜所有的bootloader應該都是用LBA去跟硬碟要boot sector,除了DOS會來看,所以只對要裝DOS的硬碟有意義。
MBR與硬碟確認
MBR(master boot record)是指如果有很多顆硬碟構成的系統,那MBR就是第一個硬碟上的第一個sector(傳統上CHA的 sector從1開始,不是0,有的bios有bug),在LBA的addressing中,就是LBA 0
BIOS裡面可以設定Boot order,那什麼是第一個硬碟呢,他會根據硬體上的回報來決定,所以不是固定的尤其在SAN的環境中可以指定SANBOOT時,即使是現在的PC環境中也有usb硬碟有可能會變成第一個硬碟。所以為了確保開機的disk是哪一個,不隨著變換disk而變化,這些無論怎樣都是根據某一個特定的獨一無二的資訊來確認硬碟,但是這個資訊寫在哪裡呢?有效範圍到哪裡呢?例如全世界的硬碟有可能都獨一無二的辨識,還是只有lab內還是只有目前這台硬碟呢?目前Linux提供下列方式。
- /dev/disk/by-id : 硬碟公司出廠
- /dev/disk/by-label : filesystem支援的,必須寫在filesystem內的特定地方。
- /dev/disk/by-path : PCI硬體的識別
- /dev/disk/by-uuid : filesystem支援的,必須寫在filesystem內的特定地方。
其中by-label其實是filesystem有支援才行,是per partition的,可以用
- mkfs -L
- mkswap -L
- blkid /dev/hda1
- dumpe2fs -h /dev/hda1 : -h 表示只要看header就好
- /lib/udev/scsi_id -g -s /block/sdc
由此看來其實最保險的是硬體上的資訊,可是卻會發生可能讀不到的情形。
Partition (Volume)與檔案系統
partition是一個硬碟上可以再做切割的單位,現在講的都是符合當年PC Microsoft定義的partitions,一個partition可以用不同的檔案系統裝上完全不一樣的作業系統。目前MBR上512bytes/partition的定義是這樣子的。
除了primary partiton還有logical partition,這都是因為當年DOS/Windows下的C: D: E:......的產物,不管如何也就是如果只有4個partition實在是太少,所以在primary partition下再指向一個新sector,這樣的partition是logical partition,logical partition可以一直串下去,也就是一個primary partiton當成一串logical partition的頭,像link list一樣的串下去。
Linux中對MBR/partition的設定為
# fdisk /dev/hda
裡面可以設定active partition (也就是booting partition),還有各partition的filesystem type。
Partition alignment
Chainload
不同的partition的第一個sector其實都是可以藏boot loader的,不管是MBR,還是一般partition。所以每個boot loader如果作的好的話,他可以把控制權交給下個partition的code去boot,這可以一直chainload下去。每個512 byte都可以是一段某個OS boot loader。再由這個 boot loader去load OS。
GPT 與boot bios partition
# gdisk /dev/sda
或者GUN parted
當然GRUB 2, syslinux, 或者GRUB 1 + 96 patch也能開GPT的資料結構。
Boot manager/Boot loader
現在的boot loader程式通常也會是boot manager了,也就是他能管理partition來load不同的kernel,作不同的系統開機。現在的boot manager/loader很厲害,能從不同地方boot系統,一般還有光碟跟網路pxeboot,光碟很像一般的硬碟,標準是El Torito,也就是在特定的LBA上去讀boot loader,pxeboot為網卡上的rom firmware裡面藏有程式,電腦硬體開機後,會去把週邊設備上的firmware load到記憶體中執行,然後向網路發出DHCP request,並獲得ip以及DHCP option中的tftpserver跟bootfile。然後再對TFTP server要求bootfile。所以一般boot loader都會提供不同boot device的boot loader,我們只要想辦法讓系統抓到他們就好。GRUB Legacy (0.97)
即使grub如此,GRUB在變化的SCSI/SAN環境中還是需要重新執行grub-install
- grub> kernel (hd0,0)/vmlinuz
- grub> initrd (hd0,0)/initrd.gz
- grub> root (hd1,2) ->指定第二台硬碟的第三partition是root
- grub> boot -> 啟動kernel
硬碟MBR
使用範例,小心,不要隨便拿來玩系統上的,不熟的人會掛掉系統- #grub-install /dev/sda 來安裝grub的code到MBR上去,也可以
- #grub-install /dev/sda1 裝到partition上去
光碟
genisoimage 主要就是用 -b來指定bootloader是哪個檔案而已,genisoimage會按照El Torito標準放到該放的第17 sector去。GRUB Legacy的是在stage2_eltorito,必須有個假的dvd root。可以自己下載來compile,裡面有stage2_eltorito,要不有裝grub在系統上就是在/usr/lib/grub/i386-pc裡面。- menu.lst跟硬碟一樣,放在~dvd_root/boot/grub/menu.list
- 把光碟bootstrap放到 ~dvd_root/boot/grub/stage2_eltorito
PXEboot
- pexboot的loader在/usr/lib/grub/i386-pc/pxegrub,把這個放到tftp server上面去,並且在dhcpd.conf的bootfile設定。
- ~tftpboot/boot/grub/menu.lst是內定的configuration檔。
boot selector configuration 檔
Grub不僅可以開機也能作boot selector,多種stage2 loader的選擇menu,主要是去讀一個 /boot/grub/menu.lst 或者 /boot/grub/grub.conf的檔案,格式為GRUB 2 (1.99)
- 跟device有關的img,也就是stage1的bootstrap,目前有boot.img cdboot.img diskboot.img lnxboot.img pxeboot.img,在/usr/lib/grub/i386-pc/
- grub內部命令處理的主體code,kernel.img,也在/usr/lib/grub/i386-pc下
- 其他特殊相關module : 例如讀取ext2檔案系統的code就獨立成為一個模組,chain load的也是一樣。如果系統有裝gurb 2 pacakge,通常會裝到/usr/lib/grub/下面去。目前有好多module,有filesystem的,有chainload的,有load背景,有i18n的等等。
git clone git://git.savannah.gnu.org/grub.git
得到最新的code。他的source code需要真的compile才會產生bootloader,不像syslinux的下載來就有binary。需要flex, bison兩個package來compile。最後在grub-core目錄裡面有boot.img cdboot.img diskboot.img lnxboot.img pxeboot.img等。這些就是跟device有關的img,而要做出一個可以boot的image,要用grub-mkimage命令來做出各種不同的booting image。每次的grub-mkimage就是把stage1.img + kernel.img + 想要的module整合成一塊新的可開機image檔。這個主要是grub 2不光光支援不同的device的stage1,他還支援不同的CPU,所以後來變這麼多種組合。否則的話,因為無論怎樣前兩個一定都是各種不同的binary,幹麼不做給user就好,而最後那個模組,也就把他寫進grub.cfg檔就好。硬碟名改變 不再由(hd0)開始,改由(hd1)表示第一硬碟。- 設定檔改變 不再是menu.lst,改叫grub.cfg,因為已經不再單純是作menu了,並且有一個grub-mkconfig命令幫忙產生。手動也是可以啦。
- 命令改變 由於GRUB 2已經不再單純的只boot linux,所以以前的kernel命令改成linux這個命令。其他的命令變得很多很複雜,也可以寫script等等。
硬碟與USB MBR
# grub-setup --root-device='(hd0,1)' /dev/sdb
# grub-install --root-directory /mnt /dev/sdb
這時會在/mnt/boot/grub下產生跟/boot/grub類似的檔案,但這時要自己去寫/mnt/boot/grub/grub.cfg。常用就兩個選項
- --directory : 告訴 grub-install 去哪找i386-pc的模組來組裝。內定是/usr/lib/grub/i386-pc
- --root-directory : 最後裝的目的地。會放在這個目錄的boot/grub下。
光碟
PXEboot
- 模組檔*.mod內定要放在~tftpboot/boot/grub/i386-pc/下面,所以如果沒有的話,是沒有辦法讀到模組啟動。
- grub.cfg檔內定在~tftpboot/boot/grub/grub.cfg
boot selector configuration檔
GRUB Shell
grub 2的啟動是當初在core.img裡面會先embedded一點點的cfg,用grub-install跟grub-setup去設定root跟prefix這兩個變數,通常是用search.fs_uuid xxxxxxxx root來設定root,然後內部會自動去insmod normal這個模組,並且用上normal命令來讀取grub.cfg,進到所謂的normal mode,但是如果讀不到就會進到rescue mode,這時grub本身內建的命令只有四個
- ls 看檔案在哪裡, ls (hd0)/boot,要使用ls必須grub能讀得懂filesystem,所以grub-install時最好都先加上--modules 'fat ext2'兩種filesystem
- insmod load模組用的,通常ls (hd0,1)/boot/grub下看到有哪些mod檔,就用insmod來load
- set/unset 用來看變數值與變數的設定,不像bourne shell,必須用set var=xxx來設定
其他的命令都會跟著相對應的mod檔案才有,例如boot linux用的boot linux initrd在linux.mod load進來後才有的。
- 類似shell的for in; do done, while ; do done, if elif else fi, case esac
- menuentry title { cmds }
syslinux
syslinux是一個很常用在光碟上與pxeboot的bootloader,但是其實他也有硬碟上的loader,只是很奇怪的是大部分硬碟用grub,光碟跟pxeboot用syslinux,主要是syslinux很久以前就能隨便由一個stage1 bootloader到另一個stage1 loader,GRUB不允許真是很奇怪。在syslinux.zytor.com下載,然後解開。裡面有各種的stage1 loader. 去下載來後解開,core裡面有mbr.bin, isolinux.bin, pxelinux.0。syslinu 4.x 不像GRUB 2太複雜到支援其他的CPU跟platform, 所以他沒有必要搞得那麼複雜,所以直接提供i386上的bootstrap就好,isolinux.bin, pxelinux.0都直接可以拿來用。syslinux是在bootloader上用模組的先驅,他提供自己的api,並在這個基礎上,提供了一些模組在com32目錄下,例如能load multiboot的mboot.c32,能夠讀懂menu命令產生menu的menu.c32,或者能解讀jpg檔使用背景圖片的vesamenu.c32等等。硬碟MBR
mbr/mbr.bin是硬碟MBR bootloader, 然後用syslinux這command把Linux loader- dd if=mbr.bin of=/dev/sda
- syslinux /dev/sda1
光碟
isolinux.bin是光碟的linux boot loader,用genisoimage裡面的選項把他寫進去光碟。必須先造一個假的dvd_root根目錄,把所有dvd檔案copy進去。裡面作個isolinux目錄,把isolinux.bin跟isolinux.cfg放到裡面。- geoisoimage -b isolinux/isolinux.bin dvd_root > dvd.iso
PXEboot
pxelinux.0是pxe boot的Linux boot loader,就是pxelinux.0,一樣要放到tftp server上的tftp根目錄去,redhat在/tftproot, debian在/var/lib/tftproot,tftproot下建立一個pxelinux.cfg的目錄,裡面有個檔案叫default就是跟syslinux.cfg類似的conf檔案。其實pxelinux的conf檔可以指定特定的mac, ipv4去讀特定的conf檔,只是我很少這麼作。boot selector configuration檔
- syslinux/syslinux.cfg
- isolinux/isolinux.cfg
- pxelinux.cfg/default
- syslinux linux/syslinux是個32位元的執行檔,如果要64位元的要自己編譯。基本參數,應該要會的。
- memdisk memdisk/memdisk可以模擬一個假disk,可以用來boot floppy或者iso image. 他這主要是攔截BIOS int 13到自己的處理routine來,不過現在的OS通常一load完前面,就進protect mode,所以int 13就失效,就看不到被int 13 mapping的drive,所以用這開iso還是有點麻煩。
- menu com32/menu/menu.c32跟vesamenu.c32是可以有漂亮的menu bar跟圖形介面模組。
- mboot com32/mboot/mboot.c32是可以用來boot所有支援multiboot規格的kernel。包括Linux, BSD, Solaris, ESX都有。
- chain com32/chain/chain.c32 是可以boot其他partition 512bytes 或其他的bootloader,這通常用來boot windows等其他bootloader。
syslinux 5
syslinux version 5.0以後也開始跟grub 2一樣玩起堆疊模組,主要是支援越來越多越來越複雜,code要重複使用等,不同地方有
- ldlinux.c32 多出一個ldlinux.c32,並要跟ldlinux.sys, isolinux.bin, pexlinux.0等放在一起
- 其他重要的libraries, libcom32.c32 libgpl.c32 liblua.c32 libutil.c32 libmenu.c32可以跟gurb 2一樣需要的才load。
- 可以用syslinux --directory /syslinux --install /dev/sdb1來安裝到/syslinux去。
- 其他功能的像vesamenu.c32在上面的c32有load進來,才能被load起來。目前的dependancy。
ipxe
pxeboot的原理很簡單就是網路卡上有一顆ROM,裡面有程式,就是買卡裡面就自然藏有的程式,就是firmware,電腦一開機後,會自動根據一些已經定好的規則跳到這些mapping到ROM上的程式執行,pxeboot的firmware要懂DHCP然後得到IP 與tftpserver IP跟bootloader,然後懂TCP/IP stack,跟tftpserver要到那個bootloader,下載後就放到特定位址,交給他執行。因為每家晶片控制方法不同,所以firmware都是硬體公司根據晶片spec寫出藏在自家卡上的(當然晶片公司都有demo公版,台灣很多公司就是拿來改改字串就叫研發)。ipxe是一個opensource的project,他嘗試根據市面上所有的spec,寫出一個可以適用很多晶片的pxe firmware,越寫越大,現在還能boot SAN HBA, iSCSI等, 而且如果原本的網路卡上沒有firmware,還可以從usb, 光碟等地方叫ipxe出來,他會想辦法去控制網路卡來得到遠端的bootloader然後開機。
ipxe 現在是qemu裡面的訂定pxe firmware,除了能自動pxeboot外,跟grub一樣可以用Ctrl-B進到他的交談模式,裡面也是一堆命令,然後這些命令也能做成script形式,讓ipxe起來後去下載來自動執行。本來pxe firmware也只是stage 1的loader,但慢慢的ipxe越寫越複雜,跟grub, syslinux一樣,也都能當成stage2的loader,也能直接boot linux kernel。
下載回來編譯出來有src/bin/{ipxe.lkrn,ipxe.usb, ipxe.iso, ipxe.pxe}可以拿來用。
命令
跟 grub2/syslinux 有很多很像,如果有的命令沒有出現的話,那就是在build的時候沒有進去,例如console命令,目前是修改src/config/general.h src/config/console.h再重新build,同樣他能boot的種類能力也在config/general.h設定,像能boot其他的pxe image這種能力,不知道將來會不會也變成像grub2/syslinux5一樣全部動態模組化,再自己load.
- dhcp 去要個 IP 回來
- route 看 ip, netmask 與 router 是誰
- kernel/imgload 這跟grub/syslinux的kernel一樣,由於他有網路功能,所以直接kernel http://xxx.xxx/linux就下載kernel回來了。
- initrd/imgfetch 這跟initrd命令一樣,同樣也可http下載。
- boot/imgexec 這跟grub2的boot一樣,跳到image去執行。
- chain chain load另一個loader,例如chain pxelinux.0,這主要可以叫用遠端一個ipxe script回來執行,chain http://xxx.xxx.xxx/myboot.ipxe。
- imgargs 給image的參數,相當於syslinux的append
- set 改變變數值。
- config 很有趣,可以全螢幕去改變內定的mac, ip, next-server等變數值。
- isset 條件判斷
- iseq 條件判斷
變數
跟 dhcpd.conf 有很多很像,這跟 grub2 一樣跟命令結合後,script 裡面可有判斷式,if 之類的與goto跳躍,甚至可以請遠端 server script 產生一個ipxe script 還回來執行。例如 chain http://xxx/boot.php?next-server=10.0.2.100&filename=mypxe.0
- mac 機器的mac address
- next-server 這就是tftpserver ip
- filename 這就是dhcp option裡面那個filename, bootfile.
使用script
- 內定使用可以直接在build binary時就放進去 => make bin/undionly.kpxe EMBED=myscript.ipxe ,這個kpxe檔要拿來燒在ROM上的。
- ipxe提供linux kernel/initrd形式的檔案,ipxe.lkrn (編譯的話在bin/ipxe.lkrn) 給grub2/syslinux的kernel 使用
- 如果已經在跑了,趕快按Ctrl-B進到命令模式,就可以自己進去使用命令chain http://myboot.ipxe去下載來跑。ipxe有個linux範例在 http://boot.ipxe.org/demo/boot.php
menu範例
主要就是用menu定義大標題,item後第一個是id第二個是title,用choose把選擇的id設定到os這個變數去,並且跳到${os}這裡面的id去,如果是debian,就一直要拿到dhcp得到的ip,然後去拿kernel, initrd最後boot。
留言列表