2009年12月25日 星期五

An Introduction to Linux Kernel Booting Sequence Part 1

此系列文章將著重於探討Linux x86核心開機過程,
其中, 假設BIOS跟Boot Loader (GRUB, for example) 運行正常, 且Boot Loader已將核心 (/boot/vmlinuz-2.6.31-16-generic) 載入記憶體並跳至載入記憶體之起始位置執行.

Linux核心主要可以分為兩大部份: 1. 執行於CPU之real mode的核心程式碼 2. 執行於CPU之protected mode的核心程式碼. 然而這兩大部份被載入至不同的記憶體區段: 1. real mode核心程式碼載入至0-640KB的某一區間, 2. protected mode核心程式碼載入至1MB記憶體位址. 如下所示:

linux kernel ram content after loading the image into the ram

Figure 1. Linux kernel RAM content after loading the Linux kernel image into RAM


首先第一個被執行的Linux核心檔案為arch/x86/boot/header.S,此檔案由組合語言所撰寫,此檔案前512位元組 (其中有15個位元組為核心標頭) 為早期的核心開機磁區,但現今的boot loader直接跳過此512位元組。緊接著在512位元組之後,即為Linux核心執行的起始點,底下展示此起始點的兩行程式碼 (以Linux核心原始碼版本2.6.31為例):
.byte 0xeb # short (2-byte) jump
.byte start_of_setup-1f


此兩行代表跳至start_of_setup標籤。".byte 0xeb" (arch/x86/boot/header.S:112)代表two-bytes jmp組合語言指令。".byte start_of_setup-1f" (arch/x86/boot/header.S:113)的"f"代表forward short jump,"start_of_setup-1"代表用"start_of_setup" (arch/x86/boot/header.S:241)標籤起始位址減去"1" (arch/x86/boot/header.S:114)標籤起始位址。

所以上述兩個位元組即代表: 以目前的位址向下跳至n個位元組 (即start_of_setup-1),因此便能正確地跳至start_of_setup標籤。

範例 (以Ubuntu 9.10之2.6.31-16-generic核心為例)

此範例利用hexdump將Linux核心dump出來,並觀看其16進制碼用以對照上述之論述。

adrian@adrian-desktop:/boot$ hexdump vmlinuz-2.6.31-16-generic > ~/vmlinuz-2.6.31-16-generic-hexdump
adrian@adrian-desktop:/boot$ gvim ~/vmlinuz-2.6.31-16-generic-hexdump

其結果如下所示:
hexdump
Figure 2. Hexdump from Linux Kernel

其中,0xAA55為Linux早期的核心開機磁區最後一個位元組(第512個位元組,arch/x86/boot/header.S:103)。0x62eb代表往下跳至62個位元組,即0x00000262位址。

本篇文章只介紹Linux之real-mode核心程式碼的entry point,往後會有陸陸續續的文章繼續探討。

【Reference】
The Kernel Boot Process

2009年12月18日 星期五

[Ubunut] 解決Firefox Flash網頁亂碼

Follow up:
1. sudo rm -f /etc/fonts/conf.d/49-sansserif.conf
2. restart firefox

大功告成.

[Reference] http://blog.xuite.net/maxkerr/blog/17037089

2009年5月21日 星期四

likely() and unlikely() macro in Linux kernel

Linux核心原始碼,經常出現兩個巨集:likely() and unlikely(),如下所示:

#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)


重點就是__builtin_expect這個函式的意義。此函式用來告訴編譯器,哪些程式區段可做預測。
底下為__builtin_expect的原型:
long __builtin_expect(long EXP, long C)
此函式__builtin_expect有兩大重點:
  1. __builtin_expect的回傳值即EXP這個判斷式。
  2. __builtin_expect語意上,是期待(EXP == C)。
例子一:
if (__builtin_expect(x, 1))
    do_something();

此敘述告知編譯器,x變數期待是1 (上述重點2), 且由於x=1, 所以__builtin_expect回傳值便是1(上述重點1),因此編譯器可以大膽預測do_something()一定會被執行到。因此便能將處理器的管線(Pipe Line)功能發揮的淋漓盡致。

例子二:
if (__builtin_expect(x, 0))
    do_something1();
else
    do_something2();

此敘述告知編譯器,x變數期待是0 (上述重點2), 且由於x=0, 所以__builtin_expect回傳值便是0(上述重點1),因此編譯器可以大膽預測do_something2()一定會被執行到,而不是預測執行do_something1()。


總結likely()與unlikely()巨集:

if(likely(x)) {
    預測想要執行的原始碼
} else {
}

if(unlikely(x)) {
} else {
    預測想要執行的原始碼
}


[Reference]
1. FAQ/LikelyUnlikely
2. richliu's blog

2009年5月19日 星期二

The Stringify Operator (#) in C

繼上次提到Token-pasting operator (##) in C文章後, 這次講一下在C語言define巨集參數使用的另一種方法, 在參數名稱前加一個#運算子, 此運算子代表所帶入的參數會被編譯器視為"字串", 所以#運算子又被稱為字串化運算子, 底下為一簡單的例子:


#define GET_RESULT(exp) printf(#exp "=%d\n", exp)

int main(void)
{
    GET_RESULT(3+2);
    return ;
}

2009年5月18日 星期一

Token-pasting operator(##) in C

我們都知道C語言define前端處理假指令用來定義變數、字串或幾行的原始碼(統稱為巨集, Macro)。
當某一巨集被定義為參數帶入之巨集, 我們最常用的就是把該參數當作變數或指標來使用,如下所示:
#define INC_IDX(val, size) (++val % size) -> 以參數為變數之值帶入此巨集
#define GET_DATA(ptr) (ptr->data) -> 以參數為指標帶入此巨集

然而,我們可以把巨集所帶入的參數當作為識別子(Token)的一部分,如下所示:
 #include <stdio.h>  
   
 int class_num = 9;  
 int class_stds = 10;  
   
 #define GET_MEMBER(postfix) class_ ## postfix  
   
 int main(void)  
 {  
    printf("class_num: %d\n", GET_MEMBER(num));  
    printf("class_stds: %d\n", GET_MEMBER(stds));  
    return 0;  
 }  
如上列所示,class_num可以經由GET_MEMBER巨集(帶入部份識別子, 也就是num)取得,此參數傳遞方法稱為Token-pasting operator,這是一個非常好用的方法, 提供給大家參考。

2008年12月19日 星期五

Linus大神的十句經典名言~

Linus的十句經典名言果然是太妙了, 噹了M$這句"Microsoft isn't evil, they just make really crappy operating systems.", 真是一針見血. 還有這句“My name is Linus, and I am your God.”, 你真的是一位大神!!

【詳情】
Linus大神十句經典名言

2008年10月16日 星期四

Hong Kong

Ha, I'm in Hong Kong airport to transit to ShangHai airport for the purpose of the business travel. By the way,I'm so lucky that I met the signer, Li-Hong Wang, at the same airplane for transiting to ShangHai airport. Haha