1.LiveCD原理php
LiveCD本質上是ISO 9660/El Torito格式的CD-ROM。html
下面對LiveCD涉及的各類技術作了簡單的調研。linux
1.1. CD-ROMgit
CD-ROM是一種光盤存儲介質。shell
與磁盤相似,CD-ROM被劃分爲多個track,track又被劃分爲多個sector。sector大小爲2352字節,隨着sector所採用的編碼方式的不一樣,其內部結構也不一樣,見下圖。CD digital audio格式是CD唱片採用的方式,CD-ROM Mode1/2是CD-ROM數據盤(LiveCD屬於此種狀況)採用的方式。ubuntu
1.2. ISO9660緩存
CD-ROM中,每一個track上均可以構建一個獨立的文件系統。ISO 9660即是一種構建在CD-ROM之上的文件系統,專爲光盤存儲介質而設計,又被稱爲CDFS(Compact Disk File System)。網絡
ISO 9660考慮了CD-ROM的順序訪問及只讀的特性,將文件連續存儲在CD-ROM的track上,對文件名的格式、屬性、大小、數量、目錄的層次等都做了限制。app
ISO 9660文件系統的存儲格式以下函數
在Data Area的頭部,有多個Volume Descriptor,其功能相似於ext4文件系統中的Super Block,用於描述當前Volume的屬性信息。
Volume是邏輯上的概念,對應到底層物理介質,就是存儲當前ISO 9660文件系統實例的CD-ROMtrack。
Volume Descriptor有多種類型,如Boot Record Volume Descriptor, PrimaryVolume Descriptor, Volume Descriptor Set Terminator等,其中Primary Volume Descriptor記錄了當前volume的大小, Root Directory的起始地址(Logical Block Address)等,ISO 9660要求至少包含一個Primary Volume Descriptor。
1.3. ElTorito
El Torito Bootable CD Specification是對ISO 9660的擴展,用於實現可引導的CD-ROM。
El Torito定義了3種引導模式,分別是floppy disk emulation, hard disk emulation以及no emulation。前兩種模擬模式,經過將軟盤或者磁盤的image存放在CD-ROM中,由BIOS負責加載到內存中,並將其虛擬成軟盤或者磁盤驅動器,而後從虛擬軟盤或虛擬磁盤中引導OS,從而實現對老OS的支持。如今最經常使用的是第3種方式,即直接從CD-ROM引導OS (LiveCD採用此方式)。El Torito Bootable CD須要BIOS的支持,固然,如今的BIOS都已經支持徹底3種引導模式了。
El Torito遵循ISO 9660的存儲格式,只是對特定區域的功能作了進一步的定義,其格式以下
El Torito將緊接着Primary Volume Descriptor的Sector 17定義爲Boot Record Volume Descriptor,其記錄了Booting Catalog的起始地址。
實際上,Boot Record Volume Descriptor並非新的VolumeDescriptor類型,其在ISO 9660中已有定義。
Booting Catalog是一個目錄表,包含了多個目錄項,目錄項進一步記錄了可引導鏡像文件的起始地址。從上圖能夠看出,El Torito支持單鏡像引導和多鏡像引導兩種模式。顧名思義,在多鏡像引導下,從一個CD-ROM能夠引導多個系統。
從ISO 9660文件系統的角度看,El Torito Bootable CD中的Booting Catalog實際上就是Root Directory文件,Bootable Disk Image以及CD-ROM Image都是文件系統中的文件,只不過是在引導階段使用的特殊文件,如bootloader等。
當從El Torito Bootable CD進行no emulation啓動時,BIOS讀取Boot Record Volume Descriptor,獲得Booting Catalog的位置並讀取此目錄表,若是發現其中包含多個Boot Entry,則須要用戶選擇一個啓動項,接着,BIOS將被選中的Boot Entry所指向的Bootable Disk Image載入內存。
須要注意的是,不管Disk Image文件有多大,BIOS都只會載入固定數量的sector,這就要求Bootable Disk Image不能太大。
載入完成以後,BIOS跳轉到Bootable Disk Image的0字節處開始執行,順序執行到代碼結束。能夠看出,Bootable Disk Image實際上就是bootloader,其須要完成OS加載和初始化的工做,因爲bootloader不能太大,所以它會進一步加載下一階段的bootloader完成複雜的工做。
1.4. ISOLINUX
isolinux是爲Linux/i386的CD-ROM啓動而設計的引導程序(bootloader),它支持以ISO 9660/El Torito的no emulation模式引導OS。
isolinux是syslinux的一部分,syslinux是一個bootloader集合,針對各類介質設計了相應的引導程序,如針對MS-DOS FAT文件系統的輕量級引導程序syslinux,針對Ext2/3/4/btrfs設計的extlinux,網絡引導程序pxelinux以及CD-ROM引導程序isolinux。
isolinux的主體是bootloader,即isolinux.bin,其負責讀取isolinux.cfg配置文件,載入相應的linux內核。isolinux.bin實現了遍歷ISO 9660文件系統的功能,所以,啓動時所需的配置,Linux內核等均可以以文件的形式存放在CD-ROM中。除了isolinux.bin和isolinux.cfg兩個文件,isolinux中還有一個重要文件,即boot.cat,即Booting Catalog,它記錄了全部可引導的文件的起始地址,對於isolinux來講,boot.cat中只記錄了isolinux.bin。
1.5. Initrd/Initramfs
1.5.1. Initrd的做用
Initrd是initial ram disk的簡稱,是Linux內核在啓動過程當中使用的臨時根文件系統,只包含必要的可執行文件和系統文件,爲掛載最終的rootfs做準備。其設計的初衷是,考慮到內核啓動時缺乏驅動,沒法訪問多數I/O外設(尤爲是存儲設備),因而在內存中虛擬一個根文件系統,使得內核能夠加載其中的驅動,執行一些初始化,進而能夠訪問外設,掛載真正的rootfs。
Initrd的目錄結構與最終的rootfs相似,但通過精簡,只包含必要的可執行文件和系統文件,如shell, mount, insmod, lvm及基本的驅動等。其中最核心的文件是init,該腳本完成內核參數的解析、驅動的加載、最終rootfs的掛載等初始化工做。
1.5.2. Initrd的原理
Linux內核支持ram disk機制,即將一段內存虛擬成塊設備(/dev/ram)。initrd基於該機制。內核在啓動時,會將initrd.img拷貝到/dev/ram上,而後將/dev/ram掛載爲rootfs。initrd.img其實是一個塊設備鏡像,在此鏡像中,保存了一個完整的文件系統(如ext2, ramfs等),將initrd.img拷貝到/dev/ram以後,/dev/ram中便包含該文件系統,以後將/dev/ram做爲一個普通的塊設備進行掛載,便可以訪問其中的文件系統。須要注意的是,爲了可以訪問該文件系統,須要將該文件系統驅動編譯到Linux內核中,而不是以可加載模塊的形式存在。
因爲ram disk是塊設備,其上層的文件系統須要在文件系統緩存和塊設備間進行數據的拷貝,實際上ram disk與文件系統緩存都在內存中,這就形成了沒必要要的數據拷貝。ramfs做爲ram disk的替代,很好地解決了這個問題。ramfs/tmpfs是內存中的文件系統,實現了文件系統的接口,並將全部文件數據保存在內存中,底層並無塊設備,無須進行緩存和塊設備間的數據交換。
1.5.3. Initramfs
Initramfs 便是基於ramfs實現了initrd的功能,二者的rootfs同樣,只是存儲格式不一樣。initramfs是一個cpio歸檔包,即直接對rootfs中的文件進行的打包,而initrd是一個img文件,是對包含rootfs的塊設備進行的鏡像拷貝。initrd和initramfs均可以進一步壓縮,在啓動時,內核會完成相應的解壓。
2.Casper
Casper是debian系統中initramfs-tools的一種hook,輔助init腳本完成LiveCD的啓動工做,主要負責rootfs的掛載和初始化。casper不只支持LiveCD,也支持Netboot tarball, USB stick image等啓動方式。
casper在initramfs的init腳本中插入相應的代碼,將init的執行邏輯導向casper中。casper會在全部塊設備中查找/casper目錄,該目錄中保存了根文件系統,一般被打包爲一個squashfs鏡像文件,找到此文件後,casper會建立一個內存文件系統,而後將squashfs解壓到此文件系統中。
init腳本主要經過/scripts/casper腳本中mountroot()函數,完成rootfs的準備工做,具體過程爲:
(1) 調用find_livefs()遍歷全部的塊設備,查找/casper/*.squashfs文件。
在遍歷過程當中,對於不一樣的塊設備,如cdrom, sata, device-mapper, md等,處理略有不一樣,但大概過程是相同的,即嘗試掛載該塊設備,而後查找該塊設備的文件系統中,是否包含合法的casper路徑(重點是查找/casper/*.squashfs文件)。
(2) 在某個塊設備中找到/casper/*.squashfs文件以後,調用setup_unionfs()將這些文件(可能有多個)以unionfs的形式掛載到/root上。
setup_unionfs()首先調用get_backing_device()將*.squashfs文件綁定到/dev/loop上,而後掛載到/$imagename目錄上,與此同時,掛載一個tmpfs,而後利用unionfs將tmpfs與/$imagename聚合到/root上。因爲設置了tmpfs爲RW權限,而/$imagename爲RO權限,使得對squashfs中文件的修改都被重定向到tmpfs中,這就解釋了爲何物理上只讀的LiveCD系統卻能夠正常讀寫。
若是向casper傳遞了toram或todisk參數,則在掛載*.squashfs文件以前,會先將這些文件拷貝到toram/todisk中,以後使用LiveCD系統的過程當中,無須再從CD-ROM讀取*.squashfs文件,提升了性能。
(3) *.squashfs掛載完成後,須要對將來的rootfs進行一些配置,這些工做由/scripts/casper-bottom中的腳本完成。
至此,casper結束執行,返回init腳本。
3.LiveCD啓動流程
BIOS讀取CD-ROM中的BootRecord Volume Descriptor,定位boot.cat文件的地址,讀取該文件中的Boot Entry,進一步定位isolinux.bin文件的地址,接着,將該文件加載到內存並執行。
isolinux.bin在光盤中查找isolinux.cfg文件,讀取該文件,得到啓動配置,該文件記錄了採用何種啓動界面,有圖形界面和者字符界面兩種,其中圖形界面下,會進一步加載vesamenu.c32文件和splash.jpg文件,完成圖形界面的顯示。在用戶選定一個啓動項以後,isolinux.bin按照isolinux.cfg中的配置,查找相應的kernel文件,將其加載到內存中,將相應的參數傳遞給kernel並執行。
kernel進行內核初始化,並將initrd.lz解壓到/dev/ram中,並將其掛載爲rootfs,執行其中的/init腳本。
init腳本解析isolinux.bin傳遞進來的內核參數,接着加載核心驅動,掛載運行時文件系統,在參數解析階段若是識別出boot=casper,init腳本會執行/scripts/casper腳本,主要調用其中mountroot()函數,實現squashfs的解壓和掛載rootfs,最後init腳本執行/bin/run-init程序,該程序完成rootfs的切換,並執行/sbin/init程序,init程序根據/etc/rc.d中的配置,進一步初始化用戶環境,包括圖形界面、網絡等。
至此,LiveCD啓動結束。
4.參考資料
http://en.wikipedia.org/wiki/CD-ROM
http://en.wikipedia.org/wiki/ISO_9660
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
http://en.wikipedia.org/wiki/El_Torito_%28CD-ROM_standard%29
http://wiki.osdev.org/El-Torito
http://download.intel.com/support/motherboards/desktop/sb/specscdrom.pdf
http://littlesvr.ca/isomaster/eltoritosuppl.php
http://www.syslinux.org/wiki/index.php/ISOLINUX
http://blog.csdn.net/liujixin8/article/details/4029887
http://manpages.ubuntu.com/manpages/hardy/man7/casper.7.html
http://en.wikipedia.org/wiki/Klibc
http://en.wikipedia.org/wiki/UnionFS