星期二, 4月 04, 2006

INITRD - embedded in kernel image

Trace 一下 initrd...


設定使用initrd後, .config
LINUX_CONFIG_ROOTFS="initrd"
CONFIG_ROOTFS_INITRD=y
在config/kernel-config-initrd ..大概會用這個作kernel defaultconfig file吧。
diff一下romfs和initrd..
CMDLINE="root=/dev/ram0 rw"
BLK_DEV_RAM=y
BLK_DEV_RAM_SIZE=4096
BLK_DEV_INITRD=y
BLK_DEV_RAMDISK_DATA=y
#BLK_DEV_BLKMEM
應該是make linux-config時,block device的"RAM disk data block compiled in"這個 option吧。
這個option configure在 drivers/block/Config.h
dep_bool 'RAM disk data block compiled in' CONFIG_BLK_DEV_RAMDISK_DATA 
所以好像有兩種initrd使用的方式:
  • 將initrd image和kernel 綁在一起。(append在kernel後面)
  • 另外存放,但是需要另外告訴kernel initrd image所在位置(memory address)
在 arch/armnommu/kernel/setup.c: setup_arh( ):
#ifdef CONFIG_BLK_DEV_INITRD
// let the kernel know where the initrd exists
#ifdef CONFIG_SD_INITRD_EMBED
{
initrd_start = (unsigned long) &__ramdisk_data;
initrd_end = (unsigned long) &__ramdisk_data_end - (unsigned long) &__ramdisk_data;
}
#else
initrd_start = CONFIG_SD_INITRD_START;
initrd_end = CONFIG_SD_INITRD_START + CONFIG_SD_INITRD_SIZE;
#endif
#endif
__ramdisk_data, __ramdisk_data_end 這兩個 label 定義在
arch/armnommu/vmlinux-armv.lds.in:
SECTIONS
{
. = TEXTADDR;
.init : { /* Init code and data */
_stext = .;

__略__

__ramdisk_data = .;
INITRDIMAGE
__ramdisk_data_end = .;

. = ALIGN(4096);

__init_end = .;
}

.可以看到在link時,會將INITRDIMAGE link進來。依照image的size決定__ramdisk_data, __ramdisk_data_end.

另一個,不將initrd 和kernel link在一起的方法,則是在configure時define CONFIG_SD_INIT_START 和 CONFIG_SD_INIT_SIZE。




所以重點就在...
  • enable kernel 對RAM disak, initrd的支援
  • 傳入適當的boot cmd
查一下cmd line parse .. (這個以前作過...)

root= 在 init/do_mounts.c : __setup("root=", root_dev_setup);
static int __init root_dev_setup(char *line)
{
int i;
char ch;

ROOT_DEV = name_to_kdev_t(line);
memset (root_device_name, 0, sizeof root_device_name);
if (strncmp (line, "/dev/", 5) == 0) line += 5;
for (i = 0; i < sizeof root_device_name - 1; ++i)
{
ch = line[i];
if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break;
root_device_name[i] = ch;
}
return 1;
}
name_to_kdev_t( )就是把 device name string轉為 device MAJ/MIN number。
kernel 認識的devname--MAJ/MIN 宣告在 root_dev_names[].

root_dev_setup( ) 由cmdline設定好 ROOT_DEV 跟 root_device_name[].

..找到這裡對initrd而言好像有點不對..

init/main.c/init( )
do_basic_setup( );   由cmdline找到root的MAJ/MIN number
prepare_namespace( );
.

完成!

linux config時要enable RAMDISK, INITRD, EMBEDDED INITRD.
進入magsi 特殊config時,要選 Embedded INITRD image.
這樣build出來的linux.bin會包含linux kernel image 和 initrd (內含root ).
用bootloader command : download net kernel linux.bin
download到kernel target(特殊address)後。
用bootloader command : boot kernel
就可以執行了。

從boot message可以看到mount initrd作root的動作。

但是奇怪的是:console竟然不能用。不能輸入。
在init.d中啟動telnetd,login是ok的。

換一個ssh開啟minicom後OK。
所以大概是VM的問題。


這樣的作法在RAM足夠多,但是flash size不夠時可以使用。
因為bootloader內含gunzip。所以整個root都可以zip起來,節省flash size。
boot後再unzip到ram中執行。
若是用romfs,因為無法kernel要直接mount,所以不能壓縮。
順便說明一下bootloader的動作:
這個bootloader要是要從flash中啟動,只有支援rootfs系統。
bootloader在flash中找romfs keyword,當作romfs起始。
再在romfs中找到linux.bin(.gz)。解開(或copy)到ram中,將控制權交給ram中的kernel。

所以即使是 linux.bin 含 initrd,要燒到flash中讓bootloader boot。也要再pack成romfs,才可以燒到flash中(雖然這個romfs中只有linux.bin一個檔案)。

沒有留言:

網誌存檔