ramdisk與 initrd、initramfs的關係

1、ramdisk、initrd是什麼?

ramdisk是一種基於內存的虛擬文件系統,通常用於放置內核的中間數據。
而initrd全稱爲"boot loader initialized RAM disk",也就是由啓動加載器所初始化的RamDisk設備,它的作用是完善內核的模塊機制,讓內核的初始化流程更具彈性;內核以及initrd,都由bootloader在機子啓動後被加載至內存的指定位置,主要功能爲按需加載模塊以及按需改變根文件系統。更詳細的內容,請參閱initrd的man手冊,裏面闡述了內核開發者對initrd制訂的功能標準。命令:man initrd

2、/dev/ram0 這個設備是哪來的?

答: 拷貝initrd內容到/dev/ram0 上時文件系統已經被加載,只是沒有設置根文件系統,內核的初始化流程還沒有進入用戶層而已,我們當然不能知道是否有這個設備,但的確是存在的。
      所謂文件系統,就是VFS,而根文件系統是其中的一個屬性項而已;而每個設備本身是內核數據區裏的一個數據結構,經過VFS的映射,才被用戶層視爲一個文件。所以,內核要創建繼而訪問一個設備,是可以直接傳遞"/dev/ram"這樣的參數給create_dev函數來實現的。
       至於設置根文件系統,只是C語言裏對一個數據結構的成員賦值而已。而所謂目錄項,也是內核數據區裏的一個數據結構。要創建/dev/ram0,只需賦值根文件系統的值,創建dev目錄項,並且創建這個ram設備即可。
      要區分內核層以及用戶層的區別,可以用一個很簡單的邏輯來解釋,試想一個,你在用戶層刪除了/dev裏的ram0,那是不是內核就沒有了這個設備了呢?再想,如果你刪除了你正在使用的硬盤的設備節點/dev/hda,那麼是不是內核就不能操作硬盤了呢?答案是很明顯的,沒有了設備節點,只意味着用戶不能操作該設備,並不代表內核不能訪問該設備。在最新的設備管理體系中,設備管理的操作邏輯是放在用戶層的,那就是udev,默認的規則中沒有/dev/eth0設備節點,但你可以照樣上網。

3、在 grub 中使用到的 initrd ,是用來做什麼的?如何做到?

答:GRUB中只是簡單地把initrd拷貝在內存中指定的位置而已,沒有對它做進一步的操作,只是將initrd的大小放在內核setup.S的頭部數據區域,由內核來初始化這段內存區域。

請看內核初始化代碼init中的initramfs.c代碼片斷:

代碼:

#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start) {
int fd;
printk(KERN_INFO "checking if image is initramfs...");
                /*這裏的initrd_start和initrd_end就是GRUB放置initrd的內存區域的範圍*/
err = unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start, 1);
if (!err) {
printk(" it is ");
unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start, 0);
free_initrd_mem(initrd_start, initrd_end);
return;
}

printk("it isn't (%s); looks like an initrd ", err);
fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700);
if (fd >= 0) {
sys_write(fd, (char *)initrd_start,
initrd_end - initrd_start);
sys_close(fd);
free_initrd_mem(initrd_start, initrd_end);
}

}

#endif

GRUB不參與Linux內核的初始化!它是與內核獨立的。

記住,GRUB與Linux內核交互的方式遵循一種協議,目前的協議版本爲2.02;GRUB通過"setup head"區域與內核交換數據。
      假設內核映像爲kernel.img,那麼這個img文件裏就包含着三截代碼段(在編譯內核的最後階段生成),第一段是bootsect.S,就是舊的內核內置啓動器,它的地位已經被GRUB替代,所以被丟棄不用;第二段是setup.S,由GRUB負責將其放置到物理地址0x90200上,它的頭部就是前面提及的所謂head區,GRUB會把需要告訴內核的信息例如initrd的物理起始地址以及大小,放在這個head區;第三段就是真正的壓縮內核映像,視乎其體積類型,如果是大內核,就將這段內核映像放至0x100000。
      那麼,在初始化頁表的時候,內核會搬動head區的數據到合適的位置,裏面的數據就會被內核初始化所利用,所以內核就得知了initrd的所有信息。
      也就是說,setup.S 前面一段是用來在grub和內核之間傳遞參數的,如果在grub 中設置了 initrd的話,grub會讀出該文件的地址以及文件的大小,然後將其寫入setup.S的head區的特定地方,待內核啓動時使用.grub引導結束後,應該跳轉至setup.S執行.

這樣的initrd.img文件是由grub載入內存,然後再將內存中的initrd信息告訴內核,讓內核進行初始化。

內核文件頭部是這樣一個數據結構:

/* For the Linux/i386 boot protocol version 2.03. */
struct linux_kernel_header
{
char code1[0x0020];
unsigned short cl_magic; /* Magic number 0xA33F */
unsigned short cl_offset; /* The offset of command line */
char code2[0x01F1 - 0x0020 - 2 - 2];
unsigned char setup_sects; /* The size of the setup in sectors */
unsigned short root_flags; /* If the root is mounted readonly */
unsigned short syssize; /* obsolete */
unsigned short swap_dev; /* obsolete */
unsigned short ram_size; /* obsolete */
unsigned short vid_mode; /* Video mode control */
unsigned short root_dev; /* Default root device number */
unsigned short boot_flag; /* 0xAA55 magic number */
unsigned short jump; /* Jump instruction */
unsigned long header; /* Magic signature "HdrS" */
unsigned short version; /* Boot protocol version supported */
unsigned long realmode_swtch; /* Boot loader hook */
unsigned long start_sys; /* Points to kernel version string */
unsigned char type_of_loader; /* Boot loader identifier */
unsigned char loadflags; /* Boot protocol option flags */
unsigned short setup_move_size; /* Move to high memory size */
unsigned long code32_start; /* Boot loader hook */
unsigned long ramdisk_image; /* initrd load address */
unsigned long ramdisk_size; /* initrd size */
unsigned long bootsect_kludge; /* obsolete */
unsigned short heap_end_ptr; /* Free memory after setup end */
unsigned short pad1; /* Unused */
char *cmd_line_ptr; /* Points to the kernel command line */
unsigned long initrd_addr_max; /* The highest address of initrd */
} __attribute__ ((packed));

grub 首先把vmlinuxz裝載入內存,然後把initrd裝載入內存,並initrd的裝載地址
填入vmlinuxz的頭部相應位置

4、grub能知道該把intrd.img這個文件放在內存的什麼地方纔安全嗎?

答:Linux爲它的啓動制訂了一個標準協議,GRUB或者LILO要啓動Linux,就必須遵循這個協議。該協議放在內核源碼目錄的"Documentation/i386/boot.txt"。
      根據這個協議,initrd的位置儘可能地放在內存的高地址,這個高地址的值取決於機器的架構,但爲了達到最大的兼容性,一般放在16MB靠後的地方,因爲16MB是i286能識別的最大內存。另外,不同的bootloader,對initrd的加載地址可能有點差異,但只要不覆蓋內核以及內核初始化可能要用的數據區即可。

5、struct linux_kernel_header在哪個文件中定義的阿?

答:grub-0.97源碼 /stage2/share.h文件中
      linux 內核 linux-2.6.18/Documentation/i386/boot.txt 也說明了頭部結構
The header looks like:

Offset Proto Name Meaning
/Size

01F1/1 ALL(1 setup_sects The size of the setup in sectors
01F2/2 ALL root_flags If set, the root is mounted readonly
01F4/4 2.04+(2 syssize The size of the 32-bit code in 16-byte paras
01F8/2 ALL ram_size DO NOT USE - for bootsect.S use only
01FA/2 ALL vid_mode Video mode control
01FC/2 ALL root_dev Default root device number
01FE/2 ALL boot_flag 0xAA55 magic number
0200/2 2.00+ jump Jump instruction
0202/4 2.00+ header Magic signature "HdrS"
0206/2 2.00+ version Boot protocol version supported
0208/4 2.00+ realmode_swtch Boot loader hook (see below)
020C/2 2.00+ start_sys The load-low segment (0x1000) (obsolete)
020E/2 2.00+ kernel_version Pointer to kernel version string
0210/1 2.00+ type_of_loader Boot loader identifier
0211/1 2.00+ loadflags Boot protocol option flags
0212/2 2.00+ setup_move_size Move to high memory size (used with hooks)
0214/4 2.00+ code32_start Boot loader hook (see below)
0218/4 2.00+ ramdisk_image initrd load address (set by boot loader)
021C/4 2.00+ ramdisk_size initrd size (set by boot loader)
0220/4 2.00+ bootsect_kludge DO NOT USE - for bootsect.S use only
0224/2 2.01+ heap_end_ptr Free memory after setup end
0226/2 N/A pad1 Unused
0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line
022C/4 2.03+ initrd_addr_max Highest legal initrd address


在文件arch/i386/boot/bootsect.S可以看到這個結構的影子

.org 497
setup_sects: .byte SETUPSECTS
root_flags: .word ROOT_RDONLY
syssize: .word SYSSIZE
swap_dev: .word SWAP_DEV
ram_size: .word RAMDISK
vid_mode: .word SVGA_MODE
root_dev: .word ROOT_DEV
boot_flag: .word 0xAA55

發佈了43 篇原創文章 · 獲贊 17 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章