2009年10月25日 星期日

initrd

Using the initial RAM disk (initrd)
/Documentation/initrd.txt
/init/do_mounts_initrd.c
/include/linux/initrd.h

linux2.6 內核的 initrd 的文件格式由原來的文件系統鏡像文件轉變成了 cpio 格式,
變化不僅反映在文件格式上, linux 內核對這兩種格式的 initrd 的處理有著截然的不同。
本文首先介紹了什麼是 initrd 技術,然後分別介紹了 Linux2.4 內核和 2.6 內核的 initrd 的處理流程。
最後通過對 Linux2.6 內核的 initrd 處理部分代碼的分析,使讀者可以對 initrd 技術有一個全面的認識。
為了更好的閱讀本文,要求讀者對 Linux 的 VFS 以及 initrd 有一個初步的瞭解。

1.什麼是 Initrd
initrd 的英文含義是 boot loader initialized RAM disk,就是由 boot loader 初始化的內存檔。
在 linux 內核啟動前, boot loader 會將存儲介質中的 initrd 文件載入到記憶體,
內核啟動時會在訪問真正的根文件系統前先訪問該記憶體中的 initrd 文件系統。
在 boot loader 配置了 initrd 的情況下,內核啟動被分成了兩個階段,
第一階段先執行 initrd 文件系統中的"某個文件",完成載入驅動模組等任務,
第二階段才會執行真正的根文件系統中的 /sbin/init 進程。
這裏提到的"某個文件",Linux2.6 內核會同以前版本內核的不同,所以這裏暫時使用了"某個文件"這個稱呼,後面會詳細講到。
第一階段啟動的目的是為第二階段的啟動掃清一切障礙,最主要的是載入根文件系統存儲介質的驅動模組。
我們知道根文件系統可以存儲在包括 IDE, SCSI, USB 在內的多種介質上,如果將這些設備的驅動都編譯進內核,可以想象內核會多麼龐大。

Initrd 的用途主要有以下四種:
1. linux 發行版的必備部件
linux 發行版必須適應各種不同的硬體架構,將所有的驅動編譯進內核是不現實的, initrd 技術是解決該問題的關鍵技術。
Linux 發行版在內核中只編譯了基本的硬體驅動,在安裝過程中通過檢測系統硬體,
生成包含安裝系統硬體驅動的 initrd, 無非是一種即可行又靈活的解決方案。
2. livecd 的必備部件
livecd 可能會面對更加複雜的硬體環境,所以必須使用 initrd.
3. 製作 Linux usb 啟動盤必須使用 initrd
usb 設備是啟動比較慢的設備,從驅動載入到設備真正可用大概需要幾秒鐘時間。
如果將 usb 驅動編譯進內核,內核通常不能成功訪問 usb 設備中的文件系統。
因為在內核訪問 usb 設備時, usb 設備通常沒有初始化完畢。
所以常規的做法是,在 initrd 中載入 usb 驅動,然後休眠幾秒中,等待 usb 設備初始化完畢後再掛載 usb 設備中的文件系統。
4. 在 linuxrc 腳本中可以很方便地始用個性化 bootsplash.

2.Linux2.4 內核對 Initrd 的處理流程
為了使讀者清晰的瞭解 Linux2.6 內核 initrd 機制的變化,在重點介紹 Linux2.6 內核 initrd 之前,先對 linux2.4 內核的 initrd 進行一個簡單的介紹。
Linux2.4 內核的 initrd 的格式是文件系統鏡像文件,本文將其稱為 image-initrd, 以區別後面介紹的 linux2.6 內核的 cpio 格式的 initrd.
linux2.4 內核對 initrd 的處理流程如下:
1. boot loader 把內核以及 /dev/initrd 的內容載入到記憶體, /dev/initrd 是由 boot loader 初始化的設備,存儲著 initrd.
2. 在內核初始化過程中,內核把 /dev/initrd 設備的內容解壓縮並拷貝到 /dev/ram0 設備上。
3. 內核以可讀寫的方式把 /dev/ram0 設備掛載為原始的根文件系統。
4. 如果 /dev/ram0 被指定為真正的根文件系統,那麼內核跳至最後一步正常啟動。
5. 執行 initrd 上的 /linuxrc 文件, linuxrc 通常是一個腳本文件,負責載入內核訪問根文件系統必須的驅動,以及載入根文件系統。
6. /linuxrc 執行完畢,真正的根文件系統被掛載。
7. 如果真正的根文件系統存在 /initrd 目錄,那麼 /dev/ram0 將從 / 移動到 /initrd。
否則如果 /initrd 目錄不存在, /dev/ram0 將被卸載。
8. 在真正的根文件系統上進行正常啟動過程 ,執行 /sbin/init.
linux2.4 內核的 initrd 的執行是作為內核啟動的一個中間階段,
也就是說 initrd 的 /linuxrc 執行以後,內核會繼續執行初始化代碼,
我們後面會看到這是 linux2.4 內核同 2.6 內核的 initrd 處理流程的一個顯著區別。

3.Linux2.6 內核對 Initrd 的處理流程
linux2.6 內核支援兩種格式的 initrd,
一種是前面第 3 部分介紹的 linux2.4 內核那種傳統格式的文件系統鏡像-image-initrd,
它的製作方法同 Linux2.4 內核的 initrd 一樣,其核心文件就是 /linuxrc。
另外一種格式的 initrd 是 cpio 格式的,這種格式的 initrd 從 linux2.5 起開始引入,
使用 cpio 工具生成,其核心文件不再是 /linuxrc, 而是 /init, 本文將這種 initrd 稱為 cpio-initrd.
儘管 linux2.6 內核對 cpio-initrd 和 image-initrd 這兩種格式的 initrd 均支援,
但對其處理流程有著顯著的區別,下面分別介紹 linux2.6 內核對這兩種 initrd 的處理流程。
cpio-initrd 的處理流程
1. boot loader 把內核以及 initrd 文件載入到記憶體的特定位置。
2. 內核判斷 initrd 的文件格式,如果是 cpio 格式。
3. 將 initrd 的內容釋放到 rootfs 中。
4. 執行 initrd 中的 /init 文件,執行到這一點,內核的工作全部結束,完全交給 /init 文件處理。
image-initrd的處理流程
1. boot loader 把內核以及 initrd 文件載入到記憶體的特定位置。
2. 內核判斷 initrd 的文件格式,如果不是 cpio 格式,將其作為 image-initrd 處理。
3. 內核將 initrd 的內容保存在 rootfs 下的 /initrd.image 文件中。
4. 內核將 /initrd.image 的內容讀入 /dev/ram0 設備中,也就是讀入了一個內存檔中。
5. 接著內核以可讀寫的方式把 /dev/ram0 設備掛載為原始的根文件系統。
6. 如果 /dev/ram0 被指定為真正的根文件系統,那麼內核跳至最後一步正常啟動。
7. 執行 initrd 上的 /linuxrc 文件, linuxrc 通常是一個腳本文件,負責載入內核訪問根文件系統必須的驅動,以及載入根文件系統。
8. /linuxrc 執行完畢,常規根文件系統被掛載.
9. 如果常規根文件系統存在 /initrd 目錄,那麼 /dev/ram0 將從/移動到 /initrd.
否則如果 /initrd 目錄不存在, /dev/ram0 將被卸載。
10. 在常規根文件系統上進行正常啟動過程,執行/sbin/init。
通過上面的流程介紹可知, Linux2.6 內核對 image-initrd 的處理流程同 linux2.4 內核相比並沒有顯著的變化,
cpio-initrd 的處理流程相比於 image-initrd 的處理流程卻有很大的區別,流程非常簡單,
在後面的源代碼分析中,讀者更能體會到處理的簡捷。

4. cpio-initrd 同 image-initrd 的區別與優勢
沒有找到正式的關於 cpio-initrd 同 image-initrd 對比的文獻,根據筆者的使用體驗以及內核代碼的分析,
總結出如下三方面的區別,這些區別也正是 cpio-initrd 的優勢所在:

I. cpio-initrd 的製作方法更加簡單
cpio-initrd 的製作非常簡單,通過兩個命令就可以完成整個製作過程
#假設當前目錄位於準備好的 initrd 文件系統的根目錄下
# find . | cpio -c -o > ../initrd.img
# gzip ../initrd.img

而傳統 initrd 的製作過程比較繁瑣,需要如下六個步驟
#假設當前目錄位於準備好的 initrd 文件系統的根目錄下
# dd if=/dev/zero of=../initrd.img bs=512k count=5
# mkfs.ext2 -F -m0 ../initrd.img
# mount -t ext2 -o loop ../initrd.img /mnt
# cp -r * /mnt
# umount /mnt
# gzip -9 ../initrd.img

本文不對上面命令的含義作細節的解釋,因為本文主要介紹的是 linux 內核對 initrd 的處理,
對上面命令不理解的讀者可以參考相關文檔。

II. cpio-initrd 的內核處理流程更加簡化
通過上面 initrd 處理流程的介紹, cpio-initrd 的處理流程顯得格外簡單,
通過對比可知 cpio-initrd 的處理流程在如下兩個方面得到了簡化:
1. cpio-initrd 並沒有使用額外的 ramdisk, 而是將其內容輸入到 rootfs 中,
其實 rootfs 本身也是一個基於記憶體的文件系統。
這樣就省掉了 ramdisk 的掛載、卸載等步驟。
2. cpio-initrd 啟動完 /init 進程,內核的任務就結束了,剩下的工作完全交給 /init 處理;
而對於 image-initrd, 內核在執行完 /linuxrc 進程後,還要進行一些收尾工作,
並且要負責執行真正的根文件系統的 /sbin/init.
通過圖 initrd_1.gif 可以更加清晰的看出處理流程的區別

III. cpio-initrd 的職責更加重要
如圖 initrd_1.gif 所示, cpio-initrd 不再像 image-initrd 那樣作為 linux 內核啟動的一個中間步驟,
而是作為內核啟動的終點,內核將控制權交給 cpio-initrd 的 /init 文件後,內核的任務就結束了,
所以在 /init 文件中,我們可以做更多的工作,而不比擔心同內核後續處理的銜接問題。
當然目前 linux 發行版的 cpio-initrd 的 /init 文件的內容還沒有本質的改變,但是相信 initrd 職責的增加一定是一個趨勢。

5. linux2.6 內核 initrd 處理的源代碼分析
對 Linuxe2.6 內核初始化部分同 initrd 密切相關的代碼給予一個比較細緻的分析,
為了講述方便,進一步明確幾個代碼分析中使用的概念:
rootfs: 一個基於記憶體的文件系統,是 linux 在初始化時載入的第一個文件系統, 關於它的進一步介紹可以參考文獻[4]。
initramfs: initramfs 同本文的主題關係不是很大,但是代碼中涉及到了 initramfs, 為了更好的理解代碼,這裏對其進行簡單的介紹。
Initramfs 是在 kernel 2.5 中引入的技術,實際上它的含義就是:
在內核鏡像中附加一個 cpio 包,這個 cpio 包中包含了一個小型的文件系統,
當內核啟動時,內核將這個 cpio 包解開,並且將其中包含的文件系統釋放到 rootfs 中,
內核中的一部分初始化代碼會放到這個文件系統中,作為用戶層進程來執行。
這樣帶來的明顯的好處是精簡了內核的初始化代碼,而且使得內核的初始化過程更容易定制。
Linux 2.6.12 內核的 initramfs 還沒有什麼實質性的東西,一個包含完整功能的 initramfs 的實現可能還需要一個緩慢的過程。
對於 initramfs 的進一步瞭解可以參考文獻[1][2][3]。
cpio-initrd: 前面已經定義過,指 linux2.6 內核使用的 cpio 格式的 initrd.
image-initrd: 前面已經定義過,專指傳統的文件鏡像格式的 initrd.
realfs: 用戶最終使用的真正的文件系統。
內核的初始化代碼位於 init/main.c 中的 static int init(void * unused) 函數中。
同 initrd 的處理相關部分函數調用層次如 initrd_2.gif 圖

init 函數是內核所有初始化代碼的入口,代碼如下,其中只保留了同 initrd 相關部分的代碼。

static int init(void * unused){
[1] populate_rootfs();
[2] if (sys_access((const char __user *) "/init", 0) == 0)
execute_command = "/init";
else
prepare_namespace();
[3] if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
(void) sys_dup(0);
(void) sys_dup(0);
[4] 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.");
}

代碼[1]: populate_rootfs 函數負責載入 initramfs 和 cpio-initrd, 對於 populate_rootfs 函數的細節後面會講到。
代碼[2]:如果 rootfs 的根目錄下中包含 /init 進程,則賦予 execute_command, 在 init 函數的末尾會被執行。
否則執行 prepare_namespace 函數, initrd 是在該函數中被載入的。
代碼[3]:將控制臺設置為標準輸入,後續的兩個 sys_dup(0), 則複製標準輸入為標準輸出和標準錯誤輸出。
代碼[4]:如果 rootfs 中存在 init 進程,就將後續的處理工作交給該 init 進程。
其實這段代碼的含義是如果載入了 cpio-initrd 則交給 cpio-initrd 中的 /init 處理,否則會執行 realfs 中的 init.
讀者可能會問:如果載入了cpio-initrd, 那麼 realfs 中的 init 進程不是沒有機會運行了嗎?
確實,如果載入了 cpio-initrd, 那麼內核就不負責執行 realfs 的 init 進程了,
而是將這個執行任務交給了cpio-initrd 的 init 進程。
解開 fedora core4 的 initrd 文件,會發現根目錄的下的 init 文件是一個腳本,在該腳本的最後一行有這樣一段代碼:

...........
switchroot --movedev /sysroot

就是 switchroot 語句負責載入 realfs, 以及執行 realfs 的 init 進程。
對 cpio-initrd 的處理
對 cpio-initrd 的處理位於 populate_rootfs 函數中。

void __init populate_rootfs(void){
[1] char *err = unpack_to_rootfs(__initramfs_start,
__initramfs_end - __initramfs_start, 0);
[2] if (initrd_start) {
[3] err = unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start, 1);
[4] if (!err) {
printk(" it is\n");
unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start, 0);
free_initrd_mem(initrd_start, initrd_end);
return;
}
[5] 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);
}
}

代碼[1]:載入 initramfs, initramfs 位於地址 __initramfs_start 處,是內核在編譯過程中生成的,
initramfs 的是作為內核的一部分而存在的,不是 boot loader 載入的。
前面提到了現在 initramfs 沒有任何實質內容。
代碼[2]:判斷是否載入了 initrd.
無論哪種格式的 initrd, 都會被 boot loader 載入到位址 initrd_start 處。
代碼[3]:判斷載入的是不是 cpio-initrd.
實際上 unpack_to_rootfs 有兩個功能一個是釋放 cpio 包,另一個就是判斷是不是 cpio 包,這是通過最後一個參數來區分的,
0: 釋放
1: 查看
代碼[4]:如果是 cpio-initrd 則將其內容釋放出來到 rootfs 中。
代碼[5]:如果不是 cpio-initrd, 則認為是一個 image-initrd, 將其內容保存到 /initrd.image 中。
在後面的 image-initrd 的處理代碼中會讀取 /initrd.image.

對 image-initrd 的處理在 prepare_namespace 函數裏,包含了對 image-initrd 進行處理的代碼,相關代碼如下:
void __init prepare_namespace(void){
[1] if (initrd_load())
goto out;
out:
umount_devfs("/dev");
[2] sys_mount(".", "/", NULL, MS_MOVE, NULL);
sys_chroot(".");
security_sb_post_mountroot();
mount_devfs_fs ();
}

代碼[1]:執行 initrd_load 函數,將 initrd 載入,如果載入成功的話 initrd_load 函數會將 realfs 的根設置為當前目錄。
代碼[2]:將當前目錄即 realfs 的根 mount Linux VFS 的根。 initrd_load 函數執行完後,將真正的文件系統的根設置為當前目錄。

initrd_load 函數負責載入 image-initrd, 代碼如下:
int __init initrd_load(void)
{
[1] if (mount_initrd) {
create_dev("/dev/ram", Root_RAM0, NULL);
[2] if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) {
sys_unlink("/initrd.image");
handle_initrd();
return 1;
}
}
sys_unlink("/initrd.image");
return 0;
}

代碼[1]:如果載入 initrd 則建立一個ram0設備 /dev/ram.
代碼[2]: /initrd.image 文件保存的就是 image-initrd, rd_load_image 函數執行具體的載入操作,將 image-nitrd 的文件內容釋放到 ram0 裏。
判斷ROOT_DEV!=Root_RAM0的含義是,如果你在grub或者lilo裏配置了 root=/dev/ram0, 則實際上真正的根設備就是 initrd 了,
所以就不把它作 initrd 處理,而是作為 realfs 處理。

handle_initrd() 函數負責對 initrd 進行具體的處理,代碼如下:
static void __init handle_initrd(void){
[1] real_root_dev = new_encode_dev(ROOT_DEV);
[2] create_dev("/dev/root.old", Root_RAM0, NULL);
mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY);
[3] sys_mkdir("/old", 0700);
root_fd = sys_open("/", 0, 0);
old_fd = sys_open("/old", 0, 0);
/* move initrd over / and chdir/chroot in initrd root */
[4] sys_chdir("/root");
sys_mount(".", "/", NULL, MS_MOVE, NULL);
sys_chroot(".");
mount_devfs_fs ();
[5] pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
if (pid > 0) {
while (pid != sys_wait4(-1, &i, 0, NULL))
yield();
}
/* move initrd to rootfs' /old */
sys_fchdir(old_fd);
sys_mount("/", ".", NULL, MS_MOVE, NULL);
/* switch root and cwd back to / of rootfs */
[6] sys_fchdir(root_fd);
sys_chroot(".");
sys_close(old_fd);
sys_close(root_fd);
umount_devfs("/old/dev");
[7] if (new_decode_dev(real_root_dev) == Root_RAM0) {
sys_chdir("/old");
return;
}
[8] ROOT_DEV = new_decode_dev(real_root_dev);
mount_root();
[9] printk(KERN_NOTICE "Trying to move old root to /initrd ... ");
error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL);
if (!error)
printk("okay\n");
else {
int fd = sys_open("/dev/root.old", O_RDWR, 0);
printk("failed\n");
printk(KERN_NOTICE "Unmounting old root\n");
sys_umount("/old", MNT_DETACH);
printk(KERN_NOTICE "Trying to free ramdisk memory ... ");
if (fd < 0) {
error = fd;
} else {
error = sys_ioctl(fd, BLKFLSBUF, 0);
sys_close(fd);
}
printk(!error ? "okay\n" : "failed\n");
}


handle_initrd 函數的主要功能是執行 initrd 的 linuxrc 文件,並且將 realfs 的根目錄設置為當前目錄。
代碼[1]: real_root_dev, 是一個總體變數保存的是 real fs 的設備號。
代碼[2]:調用 mount_block_root 函數將 initrd 文件系統掛載到了 VFS 的 /root 下。
代碼[3]:提取 rootfs 的根的文件描述符並將其保存到 root_fd.,
它的作用就是為了在 chroot 到 initrd 的文件系統,處理完 initrd 之後要,還能夠返回 rootfs.
返回的代碼參考代碼[7]。
代碼[4]: chroot 進入 initrd 的文件系統。前面 initrd 已掛載到了 rootfs的/root 目錄。
代碼[5]:執行 initrd 的 linuxrc 文件,等待其結束。
代碼[6]: initrd 處理完之後,重新 chroot 進入 rootfs.
代碼[7]:如果 real_root_dev 在 linuxrc 中重新設成 Root_RAM0, 則 initrd 就是最終的 realfs 了,改變當前目錄到 initrd 中,不作後續處理直接返回。
代碼[8]:在 linuxrc 執行完後, realfs 設備已經確定,調用 mount_root 函數將 realfs 掛載到 root_fs 的 /root 目錄下,
並將當前目錄設置為 /root.
代碼[9]:後面的代碼主要是做一些收尾的工作,將 initrd 的內存檔釋放。
到此代碼分析完畢。

6.結束語
通過本文前半部分對 cpio-initrd 和 imag-initrd 的闡述與對比以及後半部分的代碼分析,我相信讀者對 Linux 2.6 內核的 initrd 技術有了一個較為全面的瞭解。
在本文的最後,給出兩點最重要的結論:
1. 儘管 Linux2.6 既支援 cpio-initrd, 也支援 image-initrd, 但是 cpio-initrd 有著更大的優勢,
在使用中我們應該優先考慮使用 cpio 格式的 initrd.
2. cpio-initrd 相對於 image-initrd 承擔了更多的初始化責任,
這種變化也可以看作是內核代碼的用戶層化的一種體現,
我們在其他的諸如 FUSE等專案中也看到了將內核功能擴展到用戶層實現的嘗試。
精簡內核代碼,將部分功能移植到用戶層必然是linux內核發展的一個趨勢。

參考文獻[1] http://tree.celinuxforum.org/pubwiki/moin.cgi/EarlyUserSpace
[2] http://lwn.net/Articles/14776/
[3] http://www.ussg.iu.edu/hypermail/linux/kernel/0211.0/0341.html
參考文獻[4] http://www-128.ibm.com/developerworks/cn/linux/l-vfs/
[5] http://www.die.net/doc/linux/man/man4/initrd.4.html
[6] http://www.gd-linux.org/bbs/archive/index.php/t-1661.html

2009年10月4日 星期日

Windbg

[兩台電腦]
A_PC為Host,B_PC為Target
A_PC and B_PC都開啟超級終端機,Baud rate 為115200,測試是否connection.


Target端設定:
1. 編輯c:\boot.ini (此為隱藏的系統檔案,必須關閉檔案隱藏功能)
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /fastdetect /NoExecute=OptIn
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional Debug" /fastdetect /debugport=com1 /baudrate=115200
2. 重新開機,進入Windows XP debug mode

Host 端設定:
1. 建立一個windbg的shortcut
"C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" -b -k com:port=com1,baud=115200
2. 增加環境變數
變數名稱:_NT_SYMBOL_PATH
變數值:SRV*d:\symcache*http://msdl.microsoft.com/download/symbols
3. 利用shortcut啟動windbg
4. windbg->File->Image File Path,指定driver 的 .sys and .pdb








2009年6月23日 星期二

gdb遇到SIG32中斷

遇到的問題:
Program received signal SIG32, Real time event 32
解決方法:
1. handle SIG32 nostop noprintf
2. 設定breakpoint, 然後在cont

2009年6月3日 星期三

利用msmp來送Gmail e-mail

  • What is msmtp
msmtp is an SMTP client, and, in the default mode, it transmits a mail to an SMTP server ( for example at a free mail provider ) which does the delivery.
  • How to compiler msmtp on ARM platform
CC=arm-linux-gcc ./configure --host=arm-linux --with-ssl=openssl --with-libssl-prefix=openssl-0.9.7g
  • How to use msmtp
假設利用xxxx@gmail.com送一封e-mail給abcd@1234.com

1. 產生msmtprc檔案在/usr/local/etc/下
#imple for a user configuration file
# Set default values for all following accounts.
defaults
tls on
tls_certcheck off
logfile ~/.msmtp.log

# A freemail service
account gmail
host smtp.gmail.com
from YourMailAddress (xxxx@gmail.com)
auth on
user YourUserName (xxxx@gmail.com)
password YourPassword

account default : gmail
紅色的部份請填自己的資訊

2. 產生要送的mail資訊,假設為message,內容如下
Subject: my subject

body starts here
line 2
end of body

3. 執行msmtp
#./msmtp abcd@1234.com <>

--你會看到以下資訊--
<-- 220 mx.google.com ESMTP g14sm2915275rvb.22
--> EHLO localhost
<-- 250-mx.google.com at your service, [220.130.189.174]
<-- 250-SIZE 35651584
<-- 250-8BITMIME
<-- 250-STARTTLS
<-- 250-ENHANCEDSTATUSCODES
<-- 250 PIPELINING
--> STARTTLS
<-- 220 2.0.0 Ready to start TLS
TLS certificate information:
    Owner:
        Common Name: smtp.gmail.com
        Organization: Google Inc
        Locality: Mountain View
        State or Province: California
        Country: US
    Issuer:
        Common Name: Thawte Premium Server CA
        Organization: Thawte Consulting cc
        Organizational unit: Certification Services Division
        Locality: Cape Town
        State or Province: Western Cape
        Country: ZA
    Validity:
        Activation time: Mon Jul 30 00:00:00 2007
        Expiration time: Thu Jul 29 23:59:59 2010
    Fingerprints:
        SHA1: 5E:F7:E8:CE:1A:BE:D8:94:F2:77:45:5D:ED:38:46:4F:5D:D1:97:61
        MD5:  F1:D3:DE:59:9D:9C:E2:31:EA:AA:2C:A0:FC:AD:9A:61
--> EHLO localhost
<-- 250-mx.google.com at your service, [220.130.189.174]
<-- 250-SIZE 35651584
<-- 250-8BITMIME
<-- 250-AUTH LOGIN PLAIN
<-- 250-ENHANCEDSTATUSCODES
<-- 250 PIPELINING
--> AUTH PLAIN AGJpbGx3dTA3MjZAZ21haWwuY29tAGExYjJjM2Q0
<-- 235 2.7.0 Accepted
--> MAIL FROM:
--> RCPT TO:
--> DATA
<-- 250 2.1.0 OK g14sm2915275rvb.22
<-- 250 2.1.5 OK g14sm2915275rvb.22
<-- 354  Go ahead g14sm2915275rvb.22
--> Subject: my subject
-->
--> body starts here
--> line 2
--> end of body
--> .
<-- 250 2.0.0 OK 1244020638 g14sm2915275rvb.22
--> QUIT
<-- 221 2.0.0 closing connection g14sm2915275rvb.22

2009年6月2日 星期二

在 mips下 cross compiler OpenSSL

1. ./Configure linux-mips -DB_ENDIAN linux:'  mips_lexra_fp_be-gcc'
2. make

2009年5月26日 星期二

insmod module on MIPS target board 常見的錯誤

1._gp_disp symbol being undefined
_gp_disp is a magic symbol used with PIC code on MIPS. Be happy, this error message saved you from crashing your system. You should use the same compiler options to compile a kernel module as the kernel makefiles do. In particular the options -fno-pic -mno-abicalls are important.
2.xxx.o:Relocation overflow of type 4 for....

This error is caused by the limited range of relocation type 4 (R_MIPS26) which due to it's 26-bit offset only has a 28-bit reach. Modules and kernels happen to be located very far from each other and as the result this 28-bit range is insufficient. Insmod, not being stupid notices the problem and issues this error message.

The solution is the same as in the previous section. When compiling a kernel you must use the same compiler flags for modules as your actual kernel source is using in this particular kernel configuration. These are different from the flags that are used during the build of the kernel itself. In this particular case the module was built without -mlong-calls which is causing this kind of error.

2009年5月10日 星期日

Build toolchain 工具

1. buildroot (http://buildroot.uclibc.org/)
利用make menuconfig 來選擇你要的選項,例如:CPU type, gcc, glib....
並不是每個組合都是OK,有些搭配是有問題的,請先參考這篇文章(http://www.kegel.com/crosstool/crosstool-0.43/buildlogs/),小弟之前一直再蠻幹,後來才發現某些組合根本就是fail。

以上兩種build toolchain 的tool在compiler的時候,會出現gcc compiler error,尤其以新版gcc來cimpiler 舊版本gcc,時常會發現gcc語法上的錯誤,主要是因為舊版本gcc語法上較新版gcc不那麼嚴謹,所以會有錯誤發生,依照錯誤訊息,改寫一下souce code就OK,如果是錯在assembly code,你必須要有一些assembly的基礎,先試著了解code在做啥,才有辦法改寫,如果還是不行就問問google大神,祖國有很多文章可以參考,但總是不了了之,但是可以大概了結問題所在,所以也是有一點幫助。

Swap space via NFS

1. 產生swap file (32MB) 
dd if=/dev/zero of=/nfs/swap32 bs=1024k count=32
2.設定 /nfs/swap32為swap分割區
mkswap /nfs/swap32

3.將/dev/loop0與/nfs/swap32連結
losetup /dev/loop0 /nfs/swap32

4.設定 /dev/lopp0為swap分割區
mkswap /dev/loop0

5. 將/dev/loop0掛上swap
 swapon /dev/loop0



2009年2月1日 星期日

httpd 2.2.11 for mips R3000

CC=mips_lexra_fp_be-gcc ./configure --host=mips ac_cv_file__dev_zero=yes ac_cv_func_setpgrp_void=yes ac_cv_sizeof_ssize_t=4 ap_cv_void_ptr_lt_long=no

問題:
In file included from include/apr_strings.h:52,
                            from passwd/apr_getpass.c:23:
include/apr_want.h:93: redefinition of `struct iovec'
解決方法:
修改apr_want.h
#if 0
struct iovec{
...
...
}
#endif

問題:
./dftables: ./dftables: cannot execute binary file
解決方法:
用pc compiler一個x86的dftables,然後copy過來

問題:
/bin/sh: ./gen_test_char: cannot execute binary file
解決方法:
同上