2012年2月26日 星期日

kernel, initrd, root filesystem, boot loader

Boot Loader: 機器的啟動程式,可以將一些參數傳遞的給 kernel,如:root 的參數
kernel: OS 本身,會被 boot loader 讀進來
initrd: bootloader 會 load 進來,避免一些 driver 在 root filesystem 尚未 mount 時,無法取得
   ==> initrd 應該還是 kernel load 進來,因為 bootloader 應該不會管到 OS 該如何處理 initrd(否則其他 OS 該怎辦?),所以是 kernel load initrd 進來,並且執行 linuxrc 程式。
   Kernel:主要是處理真正 OS 要做的事情
   initrd:用來解決雜七雜八,但好像需要 kernel 要執行的東西,但為讓 kernel 更為乾淨,將這些東西移到  initrd 的 file system 中,該 file system 的 init 為第一個執行檔,可用來 mount 真正的 root file system。
root filesystem:OS 所需要的 file system。如:C lib 等

Ramdisk 是其中一種在記憶體上實現檔案系統的方法,一般嵌入式系統當中通常沒有硬碟的存在,但是有作業系統就會有檔案系統,因此嵌入式系統就要從記憶體裡面分出一塊區域,來做為檔案系統之用,這個區域就叫Ramdisk。


根檔案系統(Root File System、RFS)

在嵌入式系統中,並不像PC 有著大容量硬碟存在,需利用Ramdisk 模擬的方法執行系統。
Ramdisk 是利用既有的RAM 或Flash,模擬一段磁碟空間,放置Root File System 供程式執行用。

當kernel 開機完成,隨即進入RFS 內執行程式,根檔案系統內容主要如下:
/bin:放置命令檔之目錄。
/etc:放置設定檔之目錄。
/dev:放置硬體節點檔之目錄。
/lib:放置Glibc 之目錄。
/mnt:用於暫時掛載檔案系統之目錄。
/proc:Kernel 虛擬的檔案系統,提供使用者方便
觀看行程資訊與硬體狀況。

做initramfs開機時的錯誤

原因是"/"下需要有init,可以link到/sbin/init

==================================
Linux 内核启动系统时,它必须找到并执行第一个用户程序,通常是 init。
用户程序存在于文件系统,故 Linux 内核必须找到并挂载上第一个(根)文件系统,方能成功开机。

通常,可用的文件系统都列在 /etc/fstab,所以 mount 可以找到它们。但 /etc/fstab 它本身就是一个文件,存在于文件系统中。找到第一个文件系统成为鸡生蛋蛋生鸡的问题,而且为了解决它,内核开发者建立内核命令列选项 root=,用来指定 root 文件系统存在于哪个设备上


十五年前,root= 很容易解释。它可以是软盘或硬盘上的分区(Partition)
如今 root 文件系统可以存在于各种不同类型的硬件(SCSI, SATA, flash MTD) ,或是由不同类型硬件所建立的 RAID 上。

它的位置随着不同启动而不同,像可热插拔的 USB 设备被插到有多个 USB 孔的系统上 - 当有多个 USB 设备时,哪一个是正确的?

root 文件系统也可能被压缩(如何?),被加密(用什么 keys?),或 loopback 挂载(哪里?)。它甚至可以存在外部的网络服务器,需要内核去取得 DHCP 地址,完成 DNS lookup,并登入到远程服务器(需账号及密码),全部都在内核可以找到并执行第一个 userspace 程序之前。

如今,root = 已没有足够的信息。即使将所有特殊案例的行为都放进内核也无法帮助设备列举,加密,或网络登入这些随着系统不同而不同的系统。

更糟的是,替核心加入这些复杂的工作,就像是用汇编语言写 web 软件 :可以做到,但使用适当的工具会更容易完成。核心是被设计成服从命令,而不是给命令。

为了这个不断增加复杂度的工作, 核心开发者决定去寻求更好的方法来解决这整个问题。

解决方法
Linux 2.6 核心将一个小的 ram-based initial root filesystem(initramfs) 包进内核,且若这个文件系统包含一个程序 init,核心会将它当作第一个程序执行。此时,找寻其它文件系统并执行其它程序已不再是内核的问题,而是新程序的工作。

initramfs 的内容不需是一般功能。若给定系统的 root 文件系统存在于一个加密过的网络块设备,且网络地址、登入、加密都存在 USB 设备 "larry" (需密码方能存取)里,系统的 initramfs 可以有特殊功能的程序,它知道这些事,并使这可以运作。

对系统而言,不需要很大的 root 文件系统,也不需要寻址或切换到任何其它 root 文件系统。
这跟 initrd 有何不同?

Linux kernel 已经有方法提供 ram-based root filesystem,initrd 机制。对 2.4 及更早的 kernel 来说,initrd 仍然是唯一的方法去做这一连串的事。但 kernel 开发者选择在 2.6 实现一个新的机制是有原因的。

ramdisk vs ramfs
1. ramdisk (如 initrd) 是 基于ram的块设备,这表明它是一块固定大小的内存,它可以被格式化及挂载,就像磁盘一样。
这表明 ramdisk 的内容需先格式化并用特殊的工具(像是 mke2fs 及 losetup)做前置作业,而且如同所有的块设备,它需要文件系统驱动程序在执行时期解释数据。这也有人工的大小限制不论是浪费空间(若 ramdisk 没有满,已被占用的额外的内存也不能用来做其它事)或容量限制(若 ramdisk 满了,但其它仍有闲置的内存,也不能不经由重新格式化将它扩展)。

但 ramdisk 由于缓冲机制(caching)实际上浪费了更多内存。Linux 被设计为将所有的文件及目录做缓存,不论是对块设备的读出或写入,所以 Linux 复制数据到 ramdisk及从 ramdisk 复制数据出来,page cache 给 file data 用,而 dentry cache 给目录用。ramdisk 的下面则伪装为块设备。

几年前,Linus Torvalds 有一个巧妙的想法:Linux 的缓存是否可以被挂载一个文件系统?只要保持文件在缓存中且不要将它们清除,直到它们被删除或系统重新启动?Linus 写了一小段程序将缓存包起来,称它为 ramfs,而其它的 kernel 开发者建立一个加强版本称为 tmpfs(它可以写数据到 swap,及限制挂载点的大小,所以在它消耗完所有可用的内存前它会填满)。initramfs 就是 tmpfs 的一个实例。

这些基于ram 的文件系统自己改变大小以符合数据所需的大小。增加文件到 ramfs(或增大原有的文件)会自动配置更多的内存,并删除或截去文件以释放内存。在块设备及缓存间没有复制动作,因为没有实际的块设备。在缓存中的只 是数据的复制。更好的是这并不是新的程序代码,而是已存在的 Linux 缓存程序代码新的应用,这表示它几乎没有增加大小,非常简单,且基于已经历测试的基础上。

系统使用 initramfs 作为它的 root 文件系统甚至不需要将文件系统驱动程序内建到 kernel,因为没有块设备要用来做文件服务器。只是存在内存中的文件罢了。

initrd vs initramfs
底层架构的改变是 kernel 开发者建立一个新的实现的理由,但当他们在那里时他们清除了很多不好的行为及假设。

initrd 被设计为旧的 root= 的 root 设备检测程序代码的前端,而不是取代它。
它执行 /linuxrc,这被用来完成设定功能(像是登入网络,决定哪个设备含有 root 分区,或用文件做为 loopback 设备),告诉 kernel 哪个块设备含有真的 root 设备(通过写入de_t 数据到 /proc/sys/kernel/real-root-dev),且回传给 kernel,所以 kernel 可以挂载真的 root 设备及执行真的 init 程序。

这里假设“真的根设备”是块设备而不是网络共享的,同时也假设 initrd 自己不是做为真的 root 文件系统。kernel 也不会执行 /linuxrc 而做为特殊的进程(ID=1),因为这个 process ID(它有特殊的属性,像是做为唯一无法被以 kill -9 的 process) 被保留给 init,kernel 在它挂载真的 root 文件系统后会等它执行。

用 initramfs,kernel 开发者移除所有的假设。当 kernel 启动了在 initramfs 外的 /init,kernel 即做好决定并回去等待接受命令。
用 initramfs,kernel 不需要关心真的 root 档案系统在哪里,而在 initramfs 的 /init 被执行为真的 init,以 PID 1。(若 initramfs 的 init 需要不干涉特别的 PID 给其它程序,它可以用 exec() 系统呼叫,就像其它人一样)

总结
传统的 root= kernel 命令列选项仍然被支持且可用。但在开发支持initial RAM disk支持内核时,提供了许多优化和灵活性。


译者注
1. 查看initramfs的内容
# mkdir initrd
# cd intrd
# cp /boot/initrd.img initrd.img
# gunzip initrd.img
# cpio -i --make-directories < initrd.img
#

2. 创建initramfs
2.a. mkinitramf
# mkinitramfs -o /boot/initrd.img 2.6.2
Note: 2.6.25是需要创建initramfs的kernel版本号,如果是给当前kernel制作initramfs,可以用uname -r查看当前的版本号。提供kernel版本号的主要目的是为了在initramfs中添加指定kernel的驱动模块。mkinitramfs会把 /lib/modules/${kernel_version}/ 目录下的一些启动会用到的模块添加到initramfs中。
2.b. update-initramfs
更新当前kernel的initramfs
# update-initramfs -u
在添加模块时,initramfs tools只会添加一些必要模块,用户可以通过在/etc/initramfs-tools/modules文件中加入模块名称来指定必须添加的模块。
命令:mkinitramfs, update-initramfs

3. mkinitcpio
在Arch Linux中,有一个新一代的initramfs制作工具。相对于老的mkinitrd和mkinitramfs,它有以下很多优点。查看详细《使用mkinitcpio》。

参考链接:
精通initramfs构建 http://linuxman.blog.ccidnet.com/blog-htm-do-list-uid-60710-type-blog-dirid-14402.html
制作initramfs镜像 http://www.diybl.com/course/6_system/linux/Linuxjs/200888/135080.html

=====================================================


Table of Contents
I. 隨手筆記
note0002 -- initrd(initial RAM disk) 何時被 load
note0001 -- PID = 1 的 process 如何被產生

I. 隨手筆記

Table of Contents
note0002 -- initrd(initial RAM disk) 何時被 load
note0001 -- PID = 1 的 process 如何被產生

note0002


Name

note0002 -- initrd(initial RAM disk) 何時被 load

initrd(initial RAM disk) 何時被 load

在 kernel thread init 生出 user thread init 前就會先將 initrd 給載入, 這樣才有第一個 root file system。
Kernel thread init 中有一段 code:
    if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0)
    {
 ramdisk_execute_command = NULL;
 prepare_namespace();
    }
  
called functions:
    prepare_namespace()@.../init/do_mounts.c
               ↓
    initrd_load()@.../init/do_mounts_initrd.c
               ↓
    handle_initrd()@.../init/do_mounts_initrd.c
  
在 handle_initrd() 中可看到會產生一個 kernel thread 'do_linuxrc',以執行 /linuxrc 這個 script。
另外,initrd 與真正的 root file system 的先後關係看參考下圖 (取自 http://www.almesberger.net/cv/papers/ols2k-9.pdf)及 .../Document/initrd.txt。

note0001


Name

note0001 -- PID = 1 的 process 如何被產生

PID = 1 的 process 如何被產生

booting 流程正式進入 linux kernel,並執行到 start_kernel() 後,在 start_kernel() 裏的最後一步會執行 rest_init()。在 rest_init() 中會 呼叫
kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
以產生另一個 kernel thread,也就 init。注意第一個參數,實際上這個 init 是 定義在同一個檔案裏的一個 function:static int init(void * unused)。而在 init() 的最後幾行會看到以下片斷:

 if (execute_command)
  run_init_process(execute_command);

 run_init_process("/sbin/init");
 run_init_process("/etc/init");
 run_init_process("/bin/init");
 run_init_process("/bin/sh");

 panic("No init found.  Try passing init= option to kernel.");
                

run_init_process() 會嘗試執行這個四個執行檔。如果執行成功,就不會 return。 。換句話說,init()@.../init/main.c 這個 thread 會被上面四個執行檔之一給取代 掉。
所以到此時,系統中會存在二個 thread:一是 start_kernel,一是 /sbin/init (或其餘三個執行檔之一),也就是 user space 的第一個 processs (PID 為 1)。 其中,start_kernel() 最終會進入 cpu_idle()@.../arch/arm/kernel/process.c 。注意裏頭有一個無窮迴圈,start_kernel() thread 就會在這裏不斷 loop。

 start_kernel --> cpu_idle() --> loop forever
  |
  | spawned by kernel_thread()
  |
  |--> init() --> /sbin/init (1st user space process)

==========================================================

Kernel與initrd的基本建造

之前的Kernel或者initrd,我們都是拿人家已經做好的來使用而以,所以我們要來講如何用工具自己創造自己合適的kernel跟initrd.

Kernel編譯的注意事項

目前2.6的比較簡單,不用make depmod; make clean。
  • .confg 這是所有編譯的選項,可直接改裡面的參數。
    • 小心,必須不可以有重複的CONFIG_XXX存在,因為comment掉的後面會蓋掉前面的。例如

      .config

      CONFIG_IGB=m
      CONFIG_IGBVF=m
      CONFIG_IGB_DCA=y
      # CONFIG_IGB is not set
      # CONFIG_IGBVF is not set
      這樣IGB這個module是不會被compile的,所以用make menuconfig是比較簡單的。
    • kernel debug info不要編譯,會使kernel跟modules變得超級肥大。
  • make menuconfig 選擇編譯選項的Text界面,需要安裝libcurse跟tcl,也可以用存檔就是存.config
  • make bzImage 建立壓縮的kernel。make -j 8可以平行處理8個 job。
  • make modules 編譯各模組
  • make modules_install 把各模組放到/lib/modules/`uname -r`/下面去,並且建立module間的dependacny
  • depmod -a 這會重新尋找目前kernel下的所有模組,重新建立彼此的dependancy,如果你是third party的driver,基本上會放在/lib/modules/`uname -r`/extra底下,這時必須重建modules.dep。
modprobe是用來裝module的,所有的kernel模組都在/lib/modules/`uname -r`/kernel/下,以xxx.ko存在。系統一起來的時候,通常/etc/init.d/下的script會去叫modprobe,他會去下面兩個地方找相關設定
  • /etc/modprobe.conf
  • /etc/modprobe.d/xxx
modprobe.conf與modprobe.d下的檔案設定形式與格式是一樣的。
  • alias wildcard modulename : 這通常是compatible問題,以前模組名稱變化,或者長名字變短名字。
    • alias usbdevfs usbcore
    • alias nfs* nfs
    • modprobe nfs4時,其實是會帶上nfs這模組。
  • options modulename option
    • options loop max_int=16
    • modprobe loop時,會自動帶上max_int=16這個參數給loop這模組。
  • install modulename command
    • "install probe-ethernet /sbin/modprobe e100 || /sbin/modprobe eepro100"
    • modprobe probe-ethernet 將會先找e100再找eepro100
  • remove modulename command 跟install一樣只是是rmmod發生作用。
  • include filename 可以include其他的檔案。
另外debian的有一個/etc/modules這個不標準的設定,因為本來模組driver由udev來驅動,但有的模組不是硬體,所以udev無法驅動,這只有從/etc/init.d/下自己驅動,但每一個都要這麼作就要重複寫一樣的script,所以debian有一個/etc/modules來驅動純software的模組像loop這種。

kernel的參數傳遞

在grub/lilo/syslinux等Linux Loader都可以傳某些參數過去,因為這些OS dependent的loader是懂得Linux的特殊記憶體位置在做什麼的。所以像syslinux裡面可以用append來傳進去給kernel。/proc/cmdline裡面可以看到這些傳過去的參數,這些參數如果對kernel有意義,則kernel會拿進來用,如果對kernel沒有意義,則kernel會把他們放進環境變數裡面,不過最保險的方法還是去讀/proc/cmdline。因為如果不是很了解kernel,可能傳進去的剛好是某個kernel要的參數名字,那就不會出現在環境變數中了。 一些基本的kernel參數:
  • root
  • initrd
  • init
  • nfsroot

initrd探討

在作業系統沒有起來前,有些狀況是需要一個小的OS環境來作些工作的。例如全新安裝,crash急救,網路開機等等。這時我們只需要一點點的工具,然後load到記憶體中,把某段記憶體當成disk使用,就有一個小的環境跟工具可以使用了。這就是initrd (init ram disk)。這裡面其實就是一個小的暫時root file system。在boot的時候,最重要就是要掛上root file system,所以initrd裡面最重要的就是要確定最後真正root device是哪一個,並且在這小小的檔案中把負責啟動root device的driver load進來。最後再掛到真正的root去把其他的driver跟init完成。所以如果當時file system是有切割很多partiitions的,例如/var /home等等,這些都是在真實root上的/etc/fstab下設定的,只要最後進到真正的root,那麼就可以執行真正root下的init了。 root device的可能性
  • IDE/SCSI - 這會去load driver module
  • PXE NFS - 這要先把nfs root編進kernel
  • SAN boot - 跟SCSI卡的driver大同小異,一般使用者就不用管firmware怎麼implement的。
所以如果你的root device是IDE,那initrd裡面有driver了就會load進來,這時候掛上真的硬碟上的root file system,然後再一一掛上其他的driver,所以root device的driver跟其他device的driver掛上的時間點是不一樣的。root device掛上的是在initrd裡面的/lib/modules/`uname -r`/,其他的是在真正root下的/lib/module/`uname -r`/。

2.4與2.6的不同

最後雖然都是initrd但是2.4 2.6的格式與init的方法不太一樣。2.4的格式必須是一個檔案系統,2.6的支援檔案系統跟cpio形式的。都可以用gzip壓起來。
這不僅僅是格式不同,在kernel內部的處理方式也不同。
2.4的initrd是一個init ram disk, 是一個block device上掛載著一個一般的file system。
而2.6的是一個initramfs是一個rootfs的image,rootfs他是藏在kernel裡面的一個小file system就跟ext2,ext3...一樣有目錄檔案讀寫等等,不須額外編譯 ,在filesystems的link list結構裡面就自動帶有這麼一個filesystem,就像網路device自動帶有lo這個interface一樣。
rootfs是base在以前的ramfs上的,在kernel裡面的fs下面有一個ramfs這個filesystem,現在裡面init時自動會帶上一個rootfs。cpio的initramfs image展開來就load到rootfs的相對記憶體上了。

file system格式的initrd (2.4 版)

  • 使用一個ramdisk /dev/ram0來當作這個file system的block device
  • 這個file system必須在compile kernel時就要進去,不能是module,在debian通常會用cramfs。
  • 執行/linuxrc
  • /linuxrc結束時,會回到kernel,必須先用pivot_root把root掛上,kernel會認為真正的root已經掛上去了,直接執行/sbin/init為第一個user space process,
  • 使用pivot_root來改變整個系統root到真正root上面去。

cpio格式的initramfs (2.6 版)

  • 此種initrd為使用一個kernel內部rootfs的initramfs image,這是定義在kernel內部一個固定的address下。kernel會展開initrd放到特定的地方去。
  • 所以不需要特別編譯一個中介的file system到kernel內。
  • 執行/init
  • /init就是第一個user space process,不再回到kernel。必須使用klibc的run-init 或者busybox的switch_root跳到真實root file system上。並且自己執行/sbin/init。
  • rootfs的initramfs image內容無法umount,唯一能做的是delete掉所有內容來釋放記憶體。
  • 所以傳統pivot_root命令工具使用上很麻煩,必須自己implement新的流程完成,或使用新的工具,busybox提供switch_root或者klibc提供run-init命令。

解開initrd

  • kernel 2.4的initrd: # mount -o loop initrd.img /mnt/initrd
  • kernel 2.6的initrd: # gzip -dc ../initrd.gz | cpio -id --no-absolute-filenames
2.4的initrd有的mount不會自動解開gzip,所以要自己先解開。另外file system也要看有沒有load進來,像debian kernel 2.4都喜歡用cramfs來建造initrd,這就要把這個檔案系統編譯進來。
我們用debian的CDROM裡面的initrd來解開,解開後我們觀察/lib/modules/`uname -r`的driver會發現他只有放block device的跟檔案系統而已,這是因為我們只需要mount root所需要的東西就可以了。

建造initrd

建造initrd有兩種狀況,一種是要boot原本已有的系統,這需要了解不同distro的需求,好在各distro已經有script幫我們了,只要一行命令就可,另一種是我們想要自己的distribution或者我們要做自己的急救開機片,或者我們embadded系統上開機要使用,這時要自己建造一個。   

distros的initrd建造

不同的distribution有他們自己的工具創造initrd,主要是要符合自己的init程序,各家的內定init方法雖然大同小異但不是完全一樣的。還有initrd內放的軟體內容也不一樣的。
  • Debian : # mkinitrd -o xxx.img 2.6.16
  • Fedora : # mkinitrd xxx.img 2.6.18-164.el5
  • Ubuntu : # mkinitrd -o xxx.img 2.6.16
  • Centos : # mkinitrd xxx.img 2.6.18.1
好像大家的command都是mkinitrd,不過有些選項可能不太一樣。新的建造2.6的cpio/initramfs形式的initrd命令,像debian/ubuntu的已經變成mkinitramfs
  • mkinitramfs /boot/initrd-2.6.18-amd64.img 2.6.18

自己的initrd

這個主要是要有一個假的root, fakeroot, 然後在下面放很多將來開機用到的檔案,然後用cpio跟gzip捆綁起來一個檔案,initrd.img就好。這裡面的關鍵點有兩個,一個是init這隻script要做哪些重要的事情,一個就是做這些事情該放的檔案有哪些。基本上新的都已經換到cpio形式的了,所以只說明cpio /init的。 最簡單的/init就是執行一個shell,由initramfs的內容當成root filesystem,把該load的硬體driver帶上,可以把mp3的播放軟體放裡面就是小mp3播放embedded system。但是真正有用的話還是要去mount一個大root filesystem來得到更多的應用。kernel 2.6 /init要做的事情有:
  • mount proc sysfs tmpfs
  • 偵測硬體並且load root device所需drivers,例如raid, SAN HBA卡等等。就是正常Linux上的工具,現在通常用udev了。
  • 轉換到到真正的root file system並且從此以後使用這個root,這跟chroot不一樣的是chroot只是單一process的改變,而pivot_root是整個系統都變成新root。以往pivot_root是呼叫pivot_root的process繼續留在舊的root,系統變成新root,這個呼叫pivot_root的通常是個shell script,他會作一些舊root的 clean up工作,最後才chroot到新root去。
  • 清掉initrd的記憶體,以往2.4 initrd是改成新root後,還要返回kernel,由kernel去呼叫新root的/sbin/init,並且umount掉initrd,但是initramfs的initrd裡面的/init最後自己要變成root後就不返回kernel了,且initramfs是內部的一塊記憶體空間,無法umount,只能delete掉所有檔案。新工具busybox的switch_root或者klibc的run-init可以簡單一行命令的作這些事,不再用pivot_root了。
  • switch_root或run-init的stdin/stdout/stderr都需導向新root的/dev/console去。
  • 通常到新root去,從此以後就呼叫真正的BSD init或者sysV init來啟動整個系統了。
現在我們做一個自己的initrd並且用virtual machine來測試他,主要是udev, 尋找root device的kernel modules有哪些跟所需要的工具程式。
  • udev
    • 可以解開系統上的/boot下的initrd, copy /lib/udev, /etc/udev。
    • 也可用package的列出檔案方法找出,例如debian的用dpkg --listfiles udev就可以找出所有裝在系統上的bin跟lib有哪些
      • 用ldd 找出binary所需的library,copy到fakeroot去。
      • udev使用的modprobe可能有特別的參數,所以要確定他使用的工具執行起來是否是對的,busybox的有時候是不能用的。
      • 在/lib/udev/rules.d下面去grep program這個字串,會有每個rule偵測硬體所需的程式,一樣要copy出binary跟library.
  • kernel moduls
    • 用系統上的/boot下面的initrd,2.6的用gzip -dc initrd.img | cpio -i 解開
    • 然後copy裡面的lib/modules下的檔案到fakeroot去。
  • 工具程式
    • 可以用busybox,也可以copy系統上的mount, mknod, dhclient...等等東西
    • copy系統上的跟udev的一樣,用ldd 去找出bin下面的工具所需的library,copy到fakeroot去。
下面簡單例子用busybox還有udev來作工具。其中注意的是
  • busybox的switch_root需要是PID = 1的狀態,所以必須用exec來執行。
  • 我假設已經有一個建好的root在sda2上了。而且有/sbin/init在sda2上,其實就是用本來已有的linux系統來玩就可以了。
init script

/init

#!/bin/ash echo "Loading Gyoza..." export PATH=/bin:/sbin # device and pseudo filesystem dir [ -d /dev ]     || mkdir -m 0755 /dev [ -d /sys ]     || mkdir /sys [ -d /proc ]    || mkdir /proc [ -d /tmp ]     || mkdir /tmp # sysfs need by udev mount -nt sysfs none /sys mount -nt proc none /proc mount -nt tmpfs /tmp # udev for 2.6 kernel, no shm and pts any more. tmpfs_size='10m' mount -nt tmpfs -o size=$tmpfs_size,mode=0755 udev /dev # necessary dvices files in kernel for booting [ -e /dev/console ]     || mknod /dev/console c 5 1 [ -e /dev/null ]        || mknod /dev/null c 1 3 [ -e /dev/tty ]         || mknod /dev/tty c 5 0 [ -e /dev/tty0 ]        || mknod /dev/tty0 c 4 0 [ -e /dev/tty1 ]        || mknod /dev/tty1 c 4 1 # necessary devices for rescue the system [ -e /dev/sda ] || mknod /dev/sda b 8 0 [ -e /dev/sdb ] || mknod /dev/sdb b 8 16 [ -e /dev/sg0 ] || mknod /dev/sg0 c 21 0 [ -e /dev/hda ] || mknod /dev/hda b 3 0 [ -e /dev/hdb ] || mknod /dev/hdb b 3 64 [ -e /dev/hdc ] || mknod /dev/hdc b 22 0 [ -e /dev/sda1 ]        || mknod /dev/sda1 b 8 1 [ -e /dev/sda2 ]        || mknod /dev/sda2 b 8 2 [ -e /dev/sda3 ]        || mknod /dev/sda3 b 8 3 [ -e /dev/sda4 ]        || mknod /dev/sda4 b 8 4 [ -e /dev/sda5 ]        || mknod /dev/sda5 b 8 5 [ -e /dev/sda6 ]        || mknod /dev/sda6 b 8 6 # root [ -d /root ] || mkdir --m 0700 /root # var [ -d /var ] || mkdir --m 0755 /var  parse command line for gyoza distro # env passed by bootloader in /proc/cmdline for cmd in $(cat /proc/cmdline); do         case $cmd in                 *)                 echo "cmdline $cmd";                 ;;         esac done # all default variables will not be env in 2.6 # default variables from __setup() in the kernel code, so be careful echo "initrd $initrd" # load drivers necessary for booting to find the root device echo "loading... $driver" depmod -a /sbin/udevd --daemon /sbin/udevadm trigger /sbin/udevadm settle true # root=/dev/nfs and root=/dev/ram0 will be handled by kernel prepare_namespace() #  # change to real root
modprobe ext3
modprobe iso9660
mount /dev/hda1 /root
if test $? != 0; then
        mount /dev/sda1 /root
        if test $? != 0; then
                /bin/ash
        fi
fi
mount -o move /dev /root/dev
mount -o move /proc /root/proc
mount -o move /sys /root/sys
mount -o move /tmp /root/tmp
cd /root
exec switch_root . /sbin/init < dev/console > dev/console
暫時root的目錄檔案結構

initrd root

/init /dev /lib /bin /root /sys /tmp /proc
好了,我們用 $ cd fakeroot $ find . | cpio -o -H newc | gzip -9 > ../initrd.img 建造一個新的initrd.img。最後把他跟我們編譯的kernel放進到isolinux.cfg裡面或者pxeboot的pxelinux.cfg/default裡面就好。用VM開機。當然我們也可以不需要轉到一個真的root file system而繼續使用原本的rootfs就好,這通常可以用來upgrade firmware或者全新安裝一個Linux。

udev偵測硬體

在上面偵測硬體時,我們用上了現在新的udev工具,udev是user dev的意思,由於後來硬體都有所謂的熱插拔,或者像usb device可以任意時間內裝上卸除系統,所以udev可以根據硬體變化動態產生/dev/下的node。這工具的使用可以讓我們適用各種硬體,帶上所需driver,不是一開機後死死的用modprobe去load特定的硬體而已。initrd 主要要帶上的是root filesystem所在的  block  device驅動程式而已,所以我們還是可以用udev來load drivers。udev的使用為start一個udevd這個daemon,他會監視硬體變化的event,這是由kernel丟出來,然後udevd會去讀的,放到一個 queue去,然後用udevadm trigger產生cold plug,來一次性的處理這個event queue裡面的硬體,處理方式根據udev rules來處理,udev source code裡面本來就有寫好的一些rules,我們可以用這個來擴充我們的硬體rules.

udev編譯

目前他有一些dependancy,都是kernel.org下的那些相關tools,請看http://www.kernel.org/pub/linux/utils
  • 編譯一些工具
    • 在 http://www.kernel.org/pub/linux/utils 下面有很多關於kernel的utilities,去kernel/hotplug下面下載udev,基本packages目前為
      • util-linux
      • module-init-tools, 這會被libkmod取代,裡面就是modprobe...這些東西
      • usbutils (需要libusb)
      • udev (新版的請disable introspection)
編譯時要小心的是這是將來用在root的上面的,所以library相關參考位置都在/ 上,如果真的要作一份全新的,還是用Linux From Scratch先建立一個compile的tool chain, 再chroot去compile. udev compile時的configure不要忘了用configure --prefix=/usr來處理,configure --help可以看到一些compile選項。compile完後,新的udev的工具程式有udevd這個daemon跟udevadm這個管理工具程式。以及extra目錄下的一些工具。
  • udevd --daemon :使udevd成為daemon
  • udevadm command
    • udevadm trigger :  產生cold plug, 由於機器內部的硬體並沒有真正hot plug, 所以產生一個code plug來通知udev queue.
    • udevadm settle true : 檢查event queue裡面是不是真的全部結束
extra下工具主要是用來識別硬體Id的,這可以用在udev rules裡面,當看到某個id就去驅動某個driver。
  • scsi_id
  • vol_id
  • pci_id
不過新版的有的已經拿掉了,加上其他的工具,像是pci-db, usb-db之類的。

udev rules

udev會從/lib/udev/rules.d/下讀取default的rules,再從/etc/udev/rules.d下讀取custom的rules還有/dev/.udev/rules.d下讀取暫時的rules。 基本rules是一對key=value pair,用來表示符合的條件

udev rules

KERNEL=="sda", NAME="my_root_device" KERNEL=="hda", DRIVER=="ide-disk", SYMLINK+="my_local_hdd" SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST!="[module/sg]", RUN+="/sbin/modprobe sg"
其中比較重要的一些key就是
  • KERNEL
    • kernel 內部的event device 名字,例如eth0, hda, sda, sg0...這些在/dev/下原本的device名字或者網路interface名
  • SUBSYSTEMS
    • kernel 內部subsystem的event device名字,例如block, scsi, usb...等等這種device的抽象分類系統,
  • ATTR
    • /sys下面的資訊的讀取
  • SYMLINK
    • 在/dev/下給一個symbolic link名字,通常像/dev/cdrom就是這樣來的
  • RUN
    • 這就是程式執行發動者,通常modprobe就是在RUN這裡面
  • IMPORT(program)
    • 這是使用一個外部程式來得到device的properties。例如ata_id,blk_id等等來找到device的ID。
基本上這是跟kernel內部丟出來的資訊有關的,如果不是kernel developer可以先試著用
  • udevadm info -a -p /sys/
下面的目錄得到一些資訊,例如udevadm info -a -p /sys/block/sda
在以前本來是要針對每一個硬體來modprobe,後來的新版的udev對於module會去掃出來硬體device的MODALIAS,在/sys/devices/下面可以掃出所有的modalias,然後在rule中加一個modprobe $MODALIAS就好了。這個modalias可以在/lib/modules/`uname -r`/modules.alias下面看到,也可以modinfo去看一個特定的module會看到,這info是由kernel根據driver硬體產生的。這個modalias大概長這樣
pci:v00008086d00001C26sv00001458sd00005006bc0Csc03i20
只要去modprobe他也可以load上這個driver.

Busybox與klibc

在創建自己的initrd時,我們用了很多工具是一般用的,像mount, mkfs...,這些東西都很肥大,因為他們是標準工具,有很多種選項,但是其實跟微軟的office一樣,大部分時候我們只用到一小部分功能,所以有一個瑞士刀Busybox,有很多功能,甚至有web server的功能,編譯出來的code很小,我們可以用在embedded系統上. Busybox的選項跟kernel一樣在make時要設定,
$ make menuconfig
$ make
就可以產生我們想要的busybox了。
而編譯執行檔需要的library,可以選擇最小化的klibc,這個程式庫可以提供大部分的功能,也提供一些工具程式,像是cpio, dash, fstype, mkdirmknod, mount, nfsmount, run-init, etc.等等可以來mount第一個root filesystem。gcc 多加-Os這個選項。 自己的mp3 player 所以其實我們也可以做自己的mp3 player這樣的embadded system,只要我們建好vmlinuz,跟initrd,只是這個initrd裡面有init,然後他的driver module裡面有所有的相關硬體dirver,最後擺上一個播放mp3 player的軟體,機器boot之後,就進到這個mp3 player就可以了。當然如果真要量產的話,user界面要有一些按鈕,這些按鈕按一按,必須讓相對應的mp3 player軟體作業。
kernel的header有的資料結構是user space的程式有興趣的。可以make headers_install來安裝,不過通常系統中可能都有了,會放到/usr/include/linux下面。

2012年2月25日 星期六

JavaScript PC simulator

1. QEMU aothor
2. JsPCEmulator http://sourceforge.net/projects/jspcemulator/

Small Linux and BSD reference site

http://bengross.com/smallunix/

另外有一些 router 使用的 linux 或許也可以使用
http://en.wikipedia.org/wiki/List_of_Linux_router_or_firewall_distributions

Java OS

1. JX OS
2. JNode
3. JavaOS: Sun 的東西,好像沒有繼續了?
4.Sanos: 似乎可用,可以在 qemu 中執行
------------------------
5.JOS
6.SavaJe

coLinux, User mode Linux

coLinux
User mode linux (有windows 版)
都是 virtual machine to run linux

還有
plex86: 太久沒 update
bochs
wine


Dos 模擬
1. dosemu
2. dosbox
3.dodge

2012年2月20日 星期一

SysLinux


Syslinux Project 包含 lightweight bootloaders 
1. MS-DOS FAT filesystems (SYSLINUX), 
2. network booting (PXELINUX), 
3. bootable "El Torito" CD-ROMs (ISOLINUX), 
4. Linux ext2/ext3/ext4 or btrfs filesystems (EXTLINUX). 
5. The project also includes MEMDISK, a tool to boot legacy operating systems (such as DOS) from nontraditional media; it is usually used in conjunction with PXELINUX and ISOLINUX.


SYSLINUX searches for the SYSLINUX.CFG file in the following order:
/boot/syslinux/syslinux.cfg
/syslinux/syslinux.cfg
/syslinux.cfg

All filenames inside the config file are assumed to be relative to the directory SYSLINUX.CFG is in, unless preceded with a slash or backslash.
syslinux.cfg 是 text file in UNIX or DOS format.
 Keywords 是 case insensitive. 

--------------------------------------------------------
SysLinux 是一個 Linux based 的 boot loader,可以在 FAT16 中使用,USB大部分使用 FAT16

1.需在 MBR 中寫入 SysLinx 與 ldlinux.sys
2.在 USB 中 copy 進去
    a. vmlinuz -> kernel
    b. initrd.img
    c. syslinux.cfg (sysLinux 的設定檔)
    若想為這些改名,注意 sysLinux 只支援 8.3 的檔名


3.  syslinux.cfg 設定檔案應該含有下列兩行:
    default vmlinuz
    append initrd=initrd.gz ramdisk_size=12000 root=/dev/rd/0 init=/linuxrc rw
    請注意,根據開機的映像大小,在必要的時候,您可能需要增大 ramdisk_size 參數的數值。
    如果開機失敗,您可以嘗試添加 devfs=mount,dall 到 "append" 那一行。

4. 添加 ISO 映像
現在您需要把任意一個 Linux ISO 映像放入您的 USB 隨身碟內 。這樣的一個映像檔的副檔名必須是 .iso

------------------------------------------------------------------

SYSLINUX uses the syntax:
LABEL mylabel
  KERNEL mykernel
  APPEND myoptions
All options here apply to PXELINUX, ISOLINUX and EXTLINUX as well as SYSLINUX unless otherwise noted.

syslinux.cfg example:

DEFAULT linux
LABEL linux
  SAY Now booting the kernel from SYSLINUX...
  KERNEL vmlinuz.img
  APPEND ro root=/dev/sda1 initrd=initrd.img



INCLUDE filename


LABEL command: The default LABEL is "linux", but you can change this with the "DEFAULT" keyword.


KERNEL file: File SYSLINUX will boot. The "kernel" doesn't have to be a Linux kernel, it can be a boot sector or a COMBOOT file.

 none or other Linux kernel image
 .0  PXE bootstrap program (NBP) [PXELINUX only]
 .bin  "CD boot sector" [ISOLINUX only]
 .bs  Boot sector [SYSLINUX only]
 .bss  Boot sector, DOS superblock will be patched in [SYSLINUX only]
 .c32  COM32 image (32-bit COMBOOT)
 .cbt  COMBOOT image (not runnable from DOS)
 .com  COMBOOT image (runnable from DOS)
 .img  Disk image [ISOLINUX only]

LINUX image

You can use this, instead of using KERNEL file to boot a linux kernel image.

BOOT image

Bootstrap program (.bs, .bin)

BSS image

BSS image (.bss)

PXE image

PXE Network Bootstrap Program (.0)

FDIMAGE image

Floppy disk image (.img)

COMBOOT image

COMBOOT program (.com, .cbt)

COM32 image

COM32 program (.c32)

CONFIG file

CONFIG will restart the boot loader using a different configuration file.
Load new config file:
LABEL new_config
CONFIG /
Set Syslinux' home dir to and load new config file:
LABEL new_config2
CONFIG / 


APPEND options...

Adds one or more options to the kernel command line. These are added to both automatic and manual boots. The options are added at the very beginning of the kernel command line, usually permitting explicitly entered kernel options to override them. This is the equivalent of the LILO "append" option.
If you enter multiple APPEND statements in a single menu entry, only the last one will be used.

[edit]APPEND -

Append nothing. APPEND with a single hyphen as argument in a LABEL section can be used to override a global APPEND.

IPAPPEND flag_val [PXELINUX only]

The flag_val is an OR of the following options:
1: indicates that an option of the following format should be generated and added to the kernel command line:
ip=:::
... based on the input from the DHCP/BOOTP or PXE boot server.
The use of this option is not recommended. If you have to use it, it is probably an indication that your network configuration is broken. Using just ip=dhcp on the kernel command line is a preferrable option, or, better yet, run dhcpcd/dhclient, from an initrd if necessary.
2: indicates that an option of the following format should be generated and added to the kernel command line:
BOOTIF=
... in dash-separated hexadecimal with leading hardware type (same as for the configuration file; see PXELINUX documentation).
This allows an initrd program to determine which interface the system booted from.
LABEL label 
KERNEL image
  APPEND options...
  IPAPPEND flag_val [PXELINUX only] 
... indicates that if "label" is entered as the kernel to boot, SYSLINUX should instead boot "image", and the specified APPEND and IPAPPEND options should be used instead of the ones specified in the global section of the file (before the first LABEL command.) The default for "image" is the same as "label", and if no APPEND is given the default is to use the global entry (if any). Up to 128 LABEL entries are permitted. (for ISOLINUX, 64 LABEL entries.)

LOCALBOOT type [ISOLINUX, PXELINUX]

With PXELINUX, specifying "LOCALBOOT 0" instead of a "KERNEL" option means invoking this particular label will cause a local disk boot instead of booting a kernel.
  1. The argument 0 means perform a normal boot. 
  2. The argument 4 will perform a local boot with the Universal Network Driver Interface (UNDI) driver still resident in memory. 
  3. the argument 5 will perform a local boot with the entire PXE stack, including the UNDI driver, still resident in memory. 
  4. All other values are undefined. 
  • If you don't know what the UNDI or PXE stacks are, don't worry, you don't want them, just specify 0.

With ISOLINUX, the "type" specifies the local drive number to boot from; 
  • 0x00 is the primary floppy drive and 
  • 0x80 is the primary hard drive. 
  • The special value -1 causes ISOLINUX to report failure to the BIOS, which, on recent BIOSes, should mean that the next device in the boot sequence should be activated.

INITRD initrd_file

Starting with version 3.71, an initrd can be specified in a separate statement (INITRD) instead of as part of the APPEND statement. 
This functionally appends "initrd=initrd_file" to the kernel command line.
It supports multiple filenames separated by commas. This is mostly useful for initramfs, which can be composed of multiple separate cpio or cpio.gz archives
Note: all files except the last one are zero-padded to a 4K page boundary. This should not affect initramfs.

DEFAULT command

Sets the default command line. If SYSLINUX boots automatically, it will act as if the entries after DEFAULT had been typed in at the "boot:" prompt, except that the option "auto" is automatically added, indicating an automatic boot.
If no configuration file is present, or no DEFAULT entry is present in the config file, the default kernel name is "linux", with no options.

[edit]UI module options...

Selects a specific user interface module (typically menu.c32 or vesamenu.c32). The command-line interface treats this as a directive that overrides the DEFAULT and PROMPT directives.

[edit]PROMPT flag_val

If flag_val is 0, display the boot: prompt only if the Shift or Alt key is pressed, or Caps Lock or Scroll lock is set (this is the default). If flag_val is 1, always display the boot: prompt.

[edit]NOESCAPE flag_val

If flag_val is set to 1, ignore the Shift/Alt/Caps Lock/Scroll Lock escapes. Use this (together with PROMPT 0) to force the default boot selection.

[edit]NOCOMPLETE flag_val

If flag_val is set to 1, the Tab key does not display labels at the boot: prompt.

[edit]IMPLICIT flag_val

If flag_val is 0, do not load a kernel image unless it has been explicitly named in a LABEL statement. The default is 1.

ALLOWOPTIONS flag_val

If flag_val is 0, the user is not allowed to specify any arguments on the kernel command line. The only options recognized are those specified in an APPEND statement. The default is 1.

[edit]TIMEOUT timeout

Indicates how long to pause at the boot: prompt until booting automatically, in units of 1/10 s. The timeout is cancelled when any key is pressed, the assumption being the user will complete the command line. A timeout of zero will disable the timeout completely. The default is 0.
NOTE: The maximum possible timeout value is 35996. (Just under an hour.)

[edit]TOTALTIMEOUT timeout

Indicates how long to wait until booting automatically, in units of 1/10 s. This timeout is *not* cancelled by user input, and can thus be used to deal with serial port glitches or "the user walked away" type situations. A timeout of zero will disable the timeout completely. The default is 0.
Both TIMEOUT and TOTALTIMEOUT can be used together, for example:
# Wait 5 seconds unless the user types something, but
# always boot after 15 minutes.
TIMEOUT 50
TOTALTIMEOUT 9000

[edit]ONTIMEOUT kernel options...

Sets the command line invoked on a timeout. Normally this is the same thing invoked by DEFAULT. If this is specified, then DEFAULT is used only if the user presses to boot.

[edit]ONERROR kernel options...

If a kernel image is not found (either it doesn't exist, or IMPLICIT is set), run the specified command. The faulty command line is appended to the specified options, so if the ONERROR directive reads:
ONERROR xyzzy plugh 
... and the command line entered by the user is:
foo bar baz 
... SYSLINUX will execute the following as if it were entered by the user:
xyzzy plugh foo bar baz

SERIAL port [[baudrate] flowcontrol]

Enables a serial port to act as the console. "port" is a number (0 = /dev/ttyS0 = COM1, etc.) or an I/O port address (e.g. 0x3F8). If "baudrate" is omitted, the baud rate defaults to 9600 bps. The serial parameters are hardcoded to 8 bits, no parity and 1 stop bit.
"flowcontrol" is a combination of the following bits:
0x001 - Assert DTR
0x002 - Assert RTS
0x010 - Wait for CTS assertion
0x020 - Wait for DSR assertion
0x040 - Wait for RI assertion
0x080 - Wait for DCD assertion
0x100 - Ignore input unless CTS asserted
0x200 - Ignore input unless DSR asserted
0x400 - Ignore input unless RI asserted
0x800 - Ignore input unless DCD asserted
All other bits are reserved.
Typical values are:
    0 - No flow control (default)
0x303 - Null modem cable detect
0x013 - RTS/CTS flow control
0x813 - RTS/CTS flow control, modem input
0x023 - DTR/DSR flow control
0x083 - DTR/DCD flow control
For the SERIAL directive to work properly, it must be the first directive in the configuration file.
NOTE: "port" values from 0 to 3 mean the first four serial ports detected by the BIOS. They may or may not correspond to the legacy port values 0x3F8, 0x2F8, 0x3E8, 0x2E8.

[edit]CONSOLE flag_val

If flag_val is 0, disable output to the normal video console. If flag_val is 1, enable output to the video console (this is the default.) Some BIOSes try to forward this to the serial console which can make a total mess of things, so this option lets you disable the video console on these systems.

[edit]FONT filename

Load a font in .psf format before displaying any output (except the copyright line, which is output as ldlinux.sys itself is loaded.) SYSLINUX only loads the font onto the video card. If the .psf file contains a Unicode table, it is ignored. This only works on EGA and VGA cards. Hopefully, it does nothing on others.

[edit]KBDMAP keymap

Install a simple keyboard map. The keyboard remapper used is very simplistic (it simply remaps the keycodes received from the BIOS, which means that only the key combinations relevant in the default layout -- usually U.S. English -- can be mapped) but should at least help people with QWERTZ or AZERTY keyboard layouts and the locations of = and , (two special characters used heavily on the Linux kernel command line.)
The included program keytab-lilo.pl from the LILO distribution can be used to create such keymaps. The file keytab-lilo.doc contains the documentation for this program.
Syslinux also ships a comboot module named kbdmap.c32 which allows changing the keyboard mapping on the fly, making it possible to add a keyboard-selection menu and/or keyboard-selection labels from within the syslinux config file.

[edit]SAY message

Prints the message on the screen.

[edit]DISPLAY filename

Displays the indicated file on the screen at boot time (before the boot: prompt, if displayed). Please see the section below on DISPLAY files.
NOTE: If the file is missing, this option is ignored. 

[edit]F[1-12] filename

F1 filename
F2 filename
  ...etc...
F9 filename
F10 filename
F11 filename
F12 filename 
Displays the indicated file on the screen when a function key is pressed at the boot: prompt. This can be used to implement pre-boot online help (presumably for the kernel command line options).
Please see the section below on DISPLAY files.
When using the serial console, press  to get to the help screens:
<1>   to get the F1 screen
<2>   to get the F2 screen
   ...etc...
<9>   to get the F9 screen
 (or <0>) to get the F10 screen
   to get the F11 screen
   to get the F11 screen
   to get the F12 screen

[edit]Is There A Way To Define Constants Or Variables?

At present, there is no way to define constants or variables in the configuration file. That feature will be added eventually.

Can SYSLINUX Handle Large Kernels?

SYSLINUX supports large kernels (bzImage format), eliminating the 500K size limit of the zImage kernel format. bzImage format kernels are detected automatically and handled transparently to the user.
SYSLINUX also supports a boot-time-loaded ramdisk (initrd). An initrd is loaded from a DOS file if the option "initrd=filename" (where filename is the filename of the initrd image; the file must be located in the root directory on the boot floppy) is present on the processed command line (after APPEND's have been added, etc.). If several initrd options are present, the last one has precedence; this permits user-entered options to override a config file APPEND. Specifying "initrd=" without a filename inhibits initrd loading. The file specified by the initrd= option will typically be a gzipped filesystem image.
EXAMPLE (extlinux):
 APPEND ro root=/dev/hda1 initrd=/boot/initrd.img
NOTE: One of the main advantages of SYSLINUX is that it makes it very easy to support users with new or unexpected configurations, especially in a distribution setting. If initrd is used to extensively modularize the distribution kernel, it is strongly recommended that a simple way of adding drivers to the boot floppy be provided. The suggested manner is to let the initrd system mount the boot floppy and look for additional drivers in a predetermined location.
To bzImage and recent zImage kernels, SYSLINUX 1.30 and higher will identify using the ID byte 0x31. PXELINUX identifies using the ID byte 0x32, ISOLINUX 0x33, and EXTLINUX 0x34. The ID range 0x35-0x3f is reserved for future versions of derivatives of SYSLINUX.

[edit]What is the DISPLAY File Format?

DISPLAY and function-key help files are text files in either DOS or UNIX format (with or without ). In addition, the following special codes are interpreted:

[edit]Clear the screen, home the cursor:

   =  = ASCII 12
Note that the screen is filled with the current display color.
Set the display colors to the specified background and foreground colors:
   =  = ASCII 15
where and are hex digits, corresponding to the standard PC display attributes:
0 = black               8 = dark grey
1 = dark blue           9 = bright blue
2 = dark green          a = bright green
3 = dark cyan           b = bright cyan
4 = dark red            c = bright red
5 = dark purple         d = bright purple
6 = brown               e = yellow
7 = light grey          f = white
Picking a bright color (8-f) for the background results in the corresponding dark color (0-7), with the foreground flashing.
Colors are not visible over the serial console.
Example: color.txt file:
^O9eBlinking Yellow on Blue Background
# xxd color.txt
0000000: 0f39 6542 6c69 6e6b 696e 6720 5965 6c6c  .9eBlinking Yell
0000010: 6f77 206f 6e20 426c 7565 2042 6163 6b67  ow on Blue Backg
0000020: 726f 756e 640a                           round.

[edit]Display graphic from filename:

filename   =  = ASCII 24
If a VGA display is present, enter graphics mode and display the graphic included in the specified file. The file format is an ad hoc format called LSS16; the included Perl program "ppmtolss16" can be used to produce these images. This Perl program also includes the file format specification.
The image is displayed in 640x480 16-color mode. Once in graphics mode, the display attributes (set by code sequences) work slightly differently: the background color is ignored, and the foreground colors are the 16 colors specified in the image file. For that reason, ppmtolss16 allows you to specify that certain colors should be assigned to specific color indices.
Color indices 0 and 7, in particular, should be chosen with care: 0 is the background color, and 7 is the color used for the text printed by SYSLINUX itself.

[edit]Return to text mode:

   =  = ASCII 25
If we are currently in graphics mode, return to text mode. Select to which modes to print a certain part of the message:
..  .. = ASCII 16-23
These codes can be used to select which modes to print a certain part of the message file in. Each of these control characters select a specific set of modes (text screen, graphics screen, serial port) for which the output is actually displayed:
Character                       Text    Graph   Serial
------------------------------------------------------
 =  = ASCII 16     No      No      No
 =  = ASCII 17     Yes     No      No
 =  = ASCII 18     No      Yes     No
 =  = ASCII 19     Yes     Yes     No
 =  = ASCII 20     No      No      Yes
 =  = ASCII 21     Yes     No      Yes
 =  = ASCII 22     No      Yes     Yes
 =  = ASCII 23     Yes     Yes     Yes
For example:
Text modeGraphics modeSerial port
will actually print out which mode the console is in!

[edit]End of file:

   =  = ASCII 26
End of file (DOS convention).

[edit]Beep:

   =  = ASCII 7
Beep the speaker.

[edit]Write DISPLAY file with IsoLinux Mate

IsoLinux Mate (ILM) is a Windows 32-bit executable that makes it easier to write a DISPLAY file.
With ILM you can insert color commands, insert ASCII graphics with "not a real on-screen keyboard", preview your work, ..