2010年3月16日

linux kernel 下 MBR Boot flag 發揮功用

By 柯允行 2010-03-16


1前言
   這是一篇介紹如何在MSDOS MBR下利用Boot flag 80h 來引導 kernel 載入 root file system.

 首先來個Q&A自問自答,看官也可自我測試:

(1)Q:MBR(Master Boot Record)我知道,你為什麼特別提 MSDOS MBR? 難不成有很多種?  

  A:是的,我們一般在網上找到的資料幾乎都是"MSDOS MBR",它的種類可多著呢?你可以查看一下

kernel config.

(2)Q:MBR/EBR 限制的partition數目為何?

    A:因人而異,人為寫driver的人,舉例來說usb storage為最多可支援 15 partitions,原因是scsi disk driver替一支隨身碟註冊16個minor number,其中1個給disk用,15個給 partitions用.另外一個例子是mmc driver,它最多可7個partitions.當然如果你是黑客,partition數目是沒有上限的.  

 (3)Q:MBR 中的Boot flag 不就是告訴Bootstrap Loader那個partition用來當作開機磁區,你又何必多此一舉?

       A:我也想丫,但是linux boot loader,syslinux /lilo /grub,沒有支援.

(4)Q:有什麼實際應用嗎?還是你在玩玩而已.

    A:在產品軟體更新上會用到,特別是處理更新到一半斷電有用,你可以最後才把boot flag設起來,這樣子萬一發生什麼事,你的舊開機磁區仍可開機.

2案由
   syslinux /lilo /grub bootloader 都會吃一個設定檔,裏面會有一個 kernel command line,

bootloader 會把此command line傳給kernel,如下:

#start of extlinux.conf

default 1

label 1

kernel /boot/bzImage

append root=/dev/sda1 rootdelay=1 loglevel=0 pci=nommconf

#end of extlinux.conf

其中

Specify the root filesystem to boot from.

   root=device

   Tell the kernel which disk device the root filesystem image is on.

各位不難發現開機磁區便寫死為 /dev/sda1,有沒有讓MSDOS MBR Boot flag發揮的空間呢?

3解決方法
如果了解partition在kernel怎麼註冊的,這個問題就不難解決.可參考這篇(todo:細索kernel註冊partition)

筆者的想法是kernel一定有一個函式(msdos_partition)專門分析MDDOS MBR的資料,我們加入測試boot flag的機制,

如果某個分割區Boot flag=80h,就把它同時註冊到最後一個minor number的位置(/dev/sda15)

如此一來

kernel command line 永遠指向分割區Boot flag=80h

root=/dev/sda15 rootdelay=1 loglevel=0 pci=nommconf



patch如下:



--- fs/partitions/msdos.c.orig 2007-08-31 09:21:01.000000000 +0300
+++ fs/partitions/msdos.c 2007-11-13 15:25:04.000000000 +0200
@@ -417,6 +417,7 @@
unsigned char *data;
struct partition *p;
int slot;
+ int mbr_act_found;

data = read_dev_sector(bdev, 0, §);
if (!data)
@@ -464,6 +465,7 @@
* On the second pass look inside *BSD, Unixware and Solaris partitions.
*/

+ mbr_act_found=0;
state->next = 5;
for (slot = 1 ; slot <= 4 ; slot++, p++) {
u32 start = START_SECT(p)*sector_size;
@@ -480,6 +482,14 @@
continue;
}
put_partition(state, slot, start, size);
+ if (p->boot_ind == 0x80 && !mbr_act_found) {
+ // Ugly hack: put active partition always to fixed location
+ // This wont be pretty, but works for determining the "real" boot (=active) partition in boot time
+ // use slot number 15, just to be on the safe side...
+ put_partition(state,15,start,size);
+ mbr_act_found=1;
+ printk("[MBRActive]");
+ }
if (SYS_IND(p) == LINUX_RAID_PARTITION)
state->parts[slot].flags = 1;
if (SYS_IND(p) == DM6_PARTITION)



4Reference
http://mirror.href.com/thestarman/asm/mbr/PartTables3.htm#20GBpt

沒有留言: