<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6594360167010513475</id><updated>2012-01-17T14:52:05.593+08:00</updated><category term='Network Processing Improvement'/><category term='Trace code、Vim、Ctags、Cscope、Linux'/><category term='Linux、網路芳鄰、sshfs'/><category term='gpg'/><category term='most popular Linux distribution'/><category term='volatile pitfall'/><category term='Linux Vim、Plugin、Word Completion'/><category term='__initdata'/><category term='__init'/><category term='Linux Kernel、list_head、doubly linked list'/><category term='boot loader'/><category term='##'/><category term='Linux、StarDict、發音'/><category term='Ubuntu、Gvim、亂碼、Ubuntu 7.10 (Gusty'/><category term='triple XOR'/><category term='smart phone'/><category term='unlikely'/><category term='Linux Kernel、HZ、tick、jiffies'/><category term='container_of'/><category term='apt-key'/><category term='Linux Block I/O Layer'/><category term='Booting'/><category term='Linus'/><category term='Request'/><category term='Flash'/><category term='Linux Vim、Plugin、C rederence manual'/><category term='Token-pasting'/><category term='Preprocessor'/><category term='sizeof'/><category term='volatile'/><category term='debian'/><category term='Linux Block I/O Layer I/O Path'/><category term='亂碼'/><category term='define macro'/><category term='slab allocator'/><category term='Page'/><category term='Linux、Google、Google Desktop'/><category term='addition'/><category term='Acrobat Reader'/><category term='swap two variables'/><category term='stringify operator'/><category term='XOR'/><category term='protected_mode_jump'/><category term='Business Travel'/><category term='BIO (Block I/O)'/><category term='Linux 、COSCUP、ICOS、Open Source  Conference'/><category term='Chrome OS'/><category term='LDT'/><category term='setuid root'/><category term='segment selector'/><category term='Linux Distribution'/><category term='GDT'/><category term='protected-mode'/><category term='linux lookaside cache'/><category term='likely'/><category term='C Language'/><category term='OS loading'/><category term='real-mode'/><category term='Google'/><category term='ICOS、COSCUP'/><category term='free_initmem'/><category term='kmem_cache'/><category term='malloc'/><category term='sudo'/><category term='Assembly'/><category term='Firefox'/><category term='vim、source file、header file、switch'/><category term='Upgrade'/><category term='TSS (Task-State Segment)'/><category term='operating system (OS)'/><category term='Linux Kernel、skype、webcam'/><category term='call gate'/><category term='Memory Alignment'/><category term='GNU Assembler (GAS)'/><category term='Linux'/><category term='Linux Kernel'/><category term='Ubuntu'/><category term='Tablet'/><title type='text'>Adrian's Blog</title><subtitle type='html'>What a fascinating Linux it is!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>51</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-1732022582245945697</id><published>2011-08-11T20:14:00.021+08:00</published><updated>2011-08-20T00:13:02.937+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C Language'/><category scheme='http://www.blogger.com/atom/ns#' term='addition'/><category scheme='http://www.blogger.com/atom/ns#' term='XOR'/><category scheme='http://www.blogger.com/atom/ns#' term='triple XOR'/><category scheme='http://www.blogger.com/atom/ns#' term='swap two variables'/><title type='text'>[C語言] 兩變數內容值互換技巧</title><content type='html'>記得大學時, C語言課程一定會談到兩變數內容值互換技巧, 其方法利用暫存空間實現, 如底下程式碼所示:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;void swap(int *a, int *b)&lt;br /&gt;{&lt;br /&gt;  int tmp;&lt;br /&gt;&lt;br /&gt;  tmp = *a;&lt;br /&gt;  *a = *b;&lt;br /&gt;  *b = tmp;                                                                                             &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;然而, 有幾個方法不使用暫存空間便能達到此目的.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;方法一 使用三次互斥或 (Exclusive OR, XOR)&lt;br /&gt;&lt;/span&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;void swap(int *a, int *b)&lt;br /&gt;{&lt;br /&gt;  if(*a != *b) {&lt;br /&gt;      *a = *a ^ *b;&lt;br /&gt;      *b = *a ^ *b;&lt;br /&gt;      *a = *a ^ *b;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;演算式如下所示:&lt;/b&gt;&lt;br /&gt;&lt;a href="https://picasaweb.google.com/lh/photo/SZSM1H6Z-tjUkb8irXMjYg?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/-kOGZ5Fw66VE/TkXcNLVEZyI/AAAAAAAACkc/yxmD091wBZw/s800/xor_swap.jpeg" height="108" width="391" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;簡化上段程式碼: 試想底下程式碼有沒有什麼問題?&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;                                                      &lt;br /&gt;&lt;br /&gt;void swap(int *a, int *b)&lt;br /&gt;{&lt;br /&gt;  if(*a != *b)&lt;br /&gt;      *a ^= *b ^= *a ^= *b;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;  int a = 11, b = 3;&lt;br /&gt;&lt;br /&gt;  printf("===== before swapping =====\n");&lt;br /&gt;  printf("a: %d, b: %d\n", a, b);&lt;br /&gt;&lt;br /&gt;  swap(&amp;amp;a, &amp;amp;b);&lt;br /&gt;&lt;br /&gt;  printf("===== after swapping =====\n");&lt;br /&gt;  printf("a: %d, b: %d\n", a, b);&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;直接看執行結果:&lt;/b&gt;&lt;br /&gt;&lt;a href="https://picasaweb.google.com/lh/photo/9n2tueFC2VR1RSpw_-o6pA?feat=embedwebsite"&gt;&lt;img src="https://lh4.googleusercontent.com/--9HuTt6b-Z8/TkXsY0GPdwI/AAAAAAAACk0/pykT7Cpti0k/s640/swap_one_statement_result.jpeg" height="127" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;為什麼會這樣呢? 筆者將此C程式碼用gcc編譯成組合語言, 用以了解其運作邏輯, 底下為swap函式片段程式碼, 完整&lt;a href="https://docs.google.com/uc?id=0ByaIwJ06Bi-2NzFiZTU0ZWEtZjJiNC00Mzc0LTk0NjYtODBhMDA4OTljYTk4&amp;amp;export=download&amp;amp;hl=en_US"&gt;組合語言程式碼&lt;/a&gt;請按此連結下載.&lt;a href="https://picasaweb.google.com/lh/photo/AYxP6j-O95-fpKUZt4BcuA?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/-Q1AZrtDE3BA/TkX3IvwHJJI/AAAAAAAACl4/bMrwzakbaWg/s640/swap_one_statement_assembly.jpeg" height="403" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;程式堆疊示意圖&lt;/b&gt;&lt;br /&gt;&lt;a href="https://picasaweb.google.com/lh/photo/2UyacUIQHZHZoQjkT4zXyA?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/-FROdOtwLWA0/TkaiNADkK9I/AAAAAAAACm8/lD9pB4d-yYk/s640/swap_one_statement_stack.jpeg" height="312" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;程式說明:&lt;/b&gt;&lt;div&gt;由於使用一行程式碼做三次XOR, gcc編譯器會先把*a, *b, *a, *b的內容放在edx(11), ecx(3), ebx(11), eax(3)暫存器 (line 9-16), 然後再分別對這四個暫存器做三次的XOR:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;line 18-20: 第一次XOR (eax=3 XOR ebx=11), 並將其結果 (ebx=8)回存到變數a的記憶體位址, 如下圖所示: &lt;a href="https://picasaweb.google.com/lh/photo/AzwkOjQs1NFd-5z5bHhPDw?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/-4wOOedX8rIo/TkaiMlO8hQI/AAAAAAAACmw/hVmesCuoX8w/s640/swap_one_statement_1stXOR.jpeg" height="383" width="640" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;line 21-25: 第二次XOR (eax=8 XOR ecx=3),  &lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;並將其結果 (ecx=11)回存到變數b的記憶體位址, &lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;如下圖所示: &lt;a href="https://picasaweb.google.com/lh/photo/nfsesTjOV5nLamrmbabhjQ?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/-z-c5NRQ2y5U/TkaiMz39UeI/AAAAAAAACm4/KcIV1huADL8/s640/swap_one_statement_2ndXOR.jpeg" height="394" width="640" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;line 26-30: &lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;第三次XOR (eax=11 XOR edx=11), 並將其結果 (edx=0)回存到變數a的記憶體位址&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;, 如下圖所示: &lt;a href="https://picasaweb.google.com/lh/photo/XvlBXKDGw6ygM-JtM5SFKA?feat=embedwebsite"&gt;&lt;img src="https://lh6.googleusercontent.com/-VnwU-kJq66k/TkaiMyGcNXI/AAAAAAAACm0/fH3yQg47mx0/s640/swap_one_statement_3rdXOR.jpeg" height="384" width="640" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;所以問題在於, 程式設計師不能在一行程式碼中, 對同一變數做兩次的運算, 否則會造成不可預知的結果, 切記!&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;方法二 使用加減法&lt;br /&gt;&lt;/span&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;void swap(int *a, int *b)&lt;br /&gt;{&lt;br /&gt;  if(*a != *b) {&lt;br /&gt;      *a = *a + *b;&lt;br /&gt;      *b = *a - *b;&lt;br /&gt;      *a = *a - *b;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;演算式如下所示:&lt;br /&gt;&lt;/b&gt;&lt;a href="https://picasaweb.google.com/lh/photo/hniaFnES6CpFtuSNBNPGMA?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/-_GvgDq8CoUQ/TkXcM1qCltI/AAAAAAAACkc/07as5Mn4bvg/s800/add_swap.jpeg" height="102" width="391" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51);  line-height: 20px; font-size:14px;" &gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51); line-height: 20px; "&gt;&lt;span class="Apple-style-span"&gt;【Reference】&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;[1] &lt;a href="http://www.i-programmer.info/babbages-bag/498-the-magic-swap.html"&gt;XOR - the magic swap&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://everything2.com/title/XOR+swap"&gt;XOR swap &lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-1732022582245945697?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/1732022582245945697/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=1732022582245945697' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1732022582245945697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1732022582245945697'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2011/08/c.html' title='[C語言] 兩變數內容值互換技巧'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh6.googleusercontent.com/-kOGZ5Fw66VE/TkXcNLVEZyI/AAAAAAAACkc/yxmD091wBZw/s72-c/xor_swap.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-2517502415742087657</id><published>2011-08-05T19:14:00.005+08:00</published><updated>2011-08-27T10:10:45.935+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='volatile pitfall'/><category scheme='http://www.blogger.com/atom/ns#' term='volatile'/><category scheme='http://www.blogger.com/atom/ns#' term='C Language'/><title type='text'>簡介C語言volatile關鍵字及其陷阱</title><content type='html'>volatile變數代表其所儲存的內容會不定時地被改變，宣告volatile變數用來告訴編譯器 (Compiler) 不要對該變數做任何最佳化操作，凡牽涉讀取該volatile變數的操作，保證會到該變數的實體位址讀取，而不會讀取CPU暫存器的內容 (提升效能) 。舉個例子，某一硬體狀態暫存器 (Status Register)就必須宣告volatile關鍵字，因為該狀態暫存器會隨時改變，宣告volatile便可確保每次讀取的內容都是最新的。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Volatile關鍵字的應用範疇&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;1. 硬體暫存器，如狀態暫存器。&lt;br /&gt;2. 多執行緒所共用的全域變數。&lt;br /&gt;3. 中斷服務函式 (Interrupt Service Rountie，ISR)所使用的全域變數。&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Volatile陷阱&lt;/span&gt;&lt;br /&gt;想想底下範例是否有問題?&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int square(volatile int *var)&lt;br /&gt;{&lt;br /&gt;    return *var **var;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;    int    var = 5;&lt;br /&gt;&lt;br /&gt;    printf(&amp;quot;result: %d\n&amp;quot;, square(&amp;amp;var));&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;其問題在於square函式的平方算式，*var**var，此指令代表到var位址讀取其內容。然而，var位址可能儲存硬體暫存器，這些暫存器內容會隨時間而改變 (例如: 狀態暫存器)，有可能第一次讀取的時候為4, 下一次讀取為5, 導致計算出來的值不正確。&lt;br /&gt;&lt;br /&gt;因此，避免此錯誤發生便是在square函式宣告一local變數，看底下程式範例較為清楚:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int square(volatile int *var)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="font-weight:bold;"&gt;int    local_var = *var;&lt;br /&gt;&lt;br /&gt;    return local_var * local_var;&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;    int    var = 5;&lt;br /&gt;&lt;br /&gt;    printf(&amp;quot;result: %d\n&amp;quot;, square(&amp;amp;var));&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;[1] &lt;a href="http://www.netrino.com/node/80"&gt;How to Use C's volatile Keyword&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-2517502415742087657?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/2517502415742087657/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=2517502415742087657' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2517502415742087657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2517502415742087657'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2011/08/cvolatile.html' title='簡介C語言volatile關鍵字及其陷阱'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-5411842095065849258</id><published>2011-07-26T21:07:00.005+08:00</published><updated>2011-07-26T23:21:40.242+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Memory Alignment'/><title type='text'>[Linux Kernel] Allocate memory buffer whose starting address is aligned with the specific memory size</title><content type='html'>撰寫裝置驅動程式時, 常常會因為硬體需求, 需配置一塊記憶體空間用來映射至硬體的I/O或記憶體空間, 且此已配置記憶體空間的起始位址往往都必須對齊某一固定大小的記憶體。舉例來說，欲配置4906位元的記憶體空間，且起始位址需對齊16位元。底下為C語言範例程式。&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;void *memory_align(unsigned int size, unsigned int aligned_size)&lt;br /&gt;{&lt;br /&gt;    void *ptr;&lt;br /&gt;&lt;br /&gt;    unsigned int mask = ~(aligned_size -1);&lt;br /&gt;&lt;br /&gt;    if((ptr = malloc(sizeof(size + (aligned_size - 1)))) == NULL) {&lt;br /&gt;        perror(&amp;quot;memory allocation failed&amp;quot;);&lt;br /&gt;        return NULL;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    ptr = (void *) ((unsigned int) (ptr + (aligned_size - 1)) &amp;amp; mask);&lt;br /&gt;&lt;br /&gt;    return ptr;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;unsigned int mask = ~(aligned_size -1);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial, sans-serif; font-size: 13px; "&gt;此mask變數為位元遮罩, 假設aligned_size=16, 則mask=0xFFFFFFF0&lt;/span&gt;。&lt;/div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;ptr = malloc(sizeof(size + (aligned_size - 1)))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial, sans-serif; font-size: 13px; "&gt;由於我們欲讓所配置的記憶體起始位址對齊aligned_&lt;wbr&gt;size, 所以需向系統配置size+(aligned_size - 1)大小的記憶體空間&lt;/span&gt;。&lt;/div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;ptr = (void *) ((unsigned int) (ptr + (aligned_size - 1)) &amp;amp; mask);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial, sans-serif; font-size: 13px; "&gt;把所配置的記憶體起始位址加上(aligned_size - 1)，然後跟mask變數做位元遮罩，&lt;wbr&gt;如此便能取得正確的記憶體起始位址&lt;/span&gt;。&lt;/div&gt;&lt;meta equiv="content-type" content="text/html; charset=utf-8"&gt;&lt;br /&gt;下圖為詳細範例計算&lt;div&gt;&lt;a href="https://picasaweb.google.com/lh/photo/bpYeUgib9mLKfcRxyI_jWg?feat=embedwebsite"&gt;&lt;img src="https://lh3.googleusercontent.com/-DS8vp4zgdEw/Ti6-XrkOogI/AAAAAAAACiw/fqldpdOSoAI/s400/calulation.jpeg" height="400" width="302" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="https://docs.google.com/leaf?id=0ByaIwJ06Bi-2OGI0Y2QzNjAtZGRhZS00MGY4LTg2NWEtMjdhMjA1NjY3MzJh&amp;amp;hl=en_US"&gt;範例程式下載&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-5411842095065849258?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/5411842095065849258/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=5411842095065849258' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5411842095065849258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5411842095065849258'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2011/07/linux-kernel-allocate-memory-buffer.html' title='[Linux Kernel] Allocate memory buffer whose starting address is aligned with the specific memory size'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh3.googleusercontent.com/-DS8vp4zgdEw/Ti6-XrkOogI/AAAAAAAACiw/fqldpdOSoAI/s72-c/calulation.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-4493015430622169308</id><published>2010-12-28T18:16:00.004+08:00</published><updated>2010-12-28T18:44:24.474+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sudo'/><category scheme='http://www.blogger.com/atom/ns#' term='setuid root'/><title type='text'>解決"sudo: must be setuid root"的問題</title><content type='html'>今天在自己的Linux桌機 (Ubuntu 10.10) 幹了一件傻事:&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;$ sudo chown -R adrian.adrian /usr/&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;結果導致使用sudo會有底下的問題:&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;$ sudo su&lt;br /&gt;sudo: must be setuid root&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;這下可high了, Ubuntu在安裝的時候並沒有讓管理者設定root密碼, 所以無法使用root登入, 沒有root權限什麼事都不能做啊! 底下解決方式:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;重新啟動Ubuntu，在grub選單中選擇有recovery mode的選項, Ex: "Ubuntu, with Linux 2.6.35-23-server (recovery mode)"&lt;/li&gt;&lt;li&gt;以recovery模式開機後, 會出現"Recovery Menu"選單, 選擇"root     Drop to root shell prompt"選項就可進入root shell prompt。&lt;/li&gt;&lt;li&gt;利用ls -l觀看sudo資訊，所以是擁有此程式使用者的問題。&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;-rwxr-xr-x 2 adrian adrian 147872 2010-09-01 04:39 /usr/bin/sudo&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;執行底下指令便可大功告成:&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;# chwon root:root /usr/bin/sudo&lt;br /&gt;# chmod 4755 /usr/bin/sudo&lt;br /&gt;# reboot&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;最後還是乖乖地把/usr/重新設定回root。&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;$ sudo chown root.root /usr/&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;【Reference】&lt;br /&gt;[1] &lt;a href="http://ohioloco.ubuntuforums.org/showthread.php?t=219767"&gt;Ubuntu forum&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-4493015430622169308?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/4493015430622169308/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=4493015430622169308' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4493015430622169308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4493015430622169308'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/12/sudo-must-be-setuid-root.html' title='解決&quot;sudo: must be setuid root&quot;的問題'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-8408852371468883905</id><published>2010-12-21T10:09:00.018+08:00</published><updated>2010-12-25T11:41:23.036+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boot loader'/><category scheme='http://www.blogger.com/atom/ns#' term='GDT'/><category scheme='http://www.blogger.com/atom/ns#' term='call gate'/><category scheme='http://www.blogger.com/atom/ns#' term='segment selector'/><category scheme='http://www.blogger.com/atom/ns#' term='TSS (Task-State Segment)'/><category scheme='http://www.blogger.com/atom/ns#' term='protected-mode'/><category scheme='http://www.blogger.com/atom/ns#' term='operating system (OS)'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU Assembler (GAS)'/><category scheme='http://www.blogger.com/atom/ns#' term='real-mode'/><category scheme='http://www.blogger.com/atom/ns#' term='LDT'/><title type='text'>[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (七) 利用Call Gate與TSS (Task-State Segment)實現特權等級的轉換</title><content type='html'>&lt;a href="http://adrianhuang.blogspot.com/2010/12/gnu-assembler-call-gate.html"&gt;上篇文章&lt;/a&gt;僅介紹如何利用Call Gate，文中並未提及如何實現特權等級的轉換，也就是從低特權等級進入高特權等級，就如同Linux的user space (Privilege 3或稱Ring 3)進入kernel space (Privilege 0或稱Ring 0)。&lt;br /&gt;&lt;br /&gt;&lt;span &gt;&lt;span style="font-weight: bold;"&gt;簡介TSS (Task-State Segment)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;本文僅簡單說明TSS在本文被使用的地方，如欲詳盡說明請參考[2]&lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBUQhgIwAA&amp;amp;url=http%3A%2F%2Fwww.intel.com%2FAssets%2Fja_JP%2FPDF%2Fmanual%2F253668.pdf&amp;amp;ei=8e2jTM7TLorEvQOAsrynDQ&amp;amp;usg=AFQjCNGQ-LN-fJMj1hQhxGaiDArpzKB15Q&amp;amp;sig2=Q0bhLPtu2mgT6V18u9XWBw"&gt;&lt;em&gt;&lt;/em&gt;&lt;/a&gt;之第七章。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Task Structure&lt;/span&gt;&lt;br /&gt;Figure 1為一個工作任務 (Task)的結構圖，一個工作任務分為兩大部份: 1. 工作任務的執行空間 (Task Execution Space)，其中包含CS、SS以及若干個DS，也就是Figure 1右上角的三個區段。2. TSS: 由工作任務執行空間與一個儲存空間 (用來儲存工作任務的狀態)所組成。Figure 1又說明另一件事: TSS的Segment Selector必須儲存在Task Register。因此在使用TSS之前，必須使用LTR指令將TSS之Segment Selector載入至Task Register。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/CtsxqECJlUNjdkwvxrOOcg?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_VP7dWGNif7M/TRQTHjxHviI/AAAAAAAACak/PX2sd_MTkC4/s640/structure_of_a_task.jpeg" height="342" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 1 Structure of a Task&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;TSS Memory Layout&lt;/span&gt;&lt;br /&gt;Figure 2為32位元TSS記憶體空間配置圖，如下所述:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ESP0、SS0、ESP1、SS1、ESP2與SS2: 分別為特權等級0、1與2的堆疊區段與堆疊指標，也就是Figure 1右下角三個 "Stack Seg. Priv. Level x"。本文利用ESP0與SS0實現特權等級的轉換 (Ring 3轉換至Ring 0)，因此作者僅設定TSS的這兩個欄位，其它欄位則設為0。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;其它欄位在此不進一步探討，有興趣的網友可以參考[2]。&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span &gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;div style="text-align: center;"&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/fhXs252Ib6Fogui1b5RS4w?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_VP7dWGNif7M/TRQTHu8W_uI/AAAAAAAACao/zUtGEv44HLI/s640/TSS_memory_layout.jpeg" height="640" width="493" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-weight: bold;"&gt;Figure 2 TSS Memory Layout&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" &gt;原始碼下載&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;由於篇幅的關係，往後該系列文章將不張貼程式碼，將提供連結下載方式，&lt;a href="http://hpds.ee.ncku.edu.tw/~adrian/blog_archive/os_dev/pe-call-gate-tss.tar.gz"&gt;原始碼下載點&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span &gt;&lt;span style="font-weight: bold;"&gt;作業系統程式碼說明&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Figure 3為作業系統程式碼解說圖，此圖說明GDT與LDT的記憶體配置圖與程式流程圖，其流程圖並非以傳統方式表示。取而代之，改以紅色圈圈的數字代表程式流程並搭配GDT與LDT記憶體配置圖，如此更能清楚地明白程式執行流程。底下將針對每一步驟 (紅色圈圈的數字)做詳盡的解釋:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="text-decoration: underline;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/B_6Ao9mjUHX5oBrtxQ5CNw?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_VP7dWGNif7M/TRRZPyR-OAI/AAAAAAAACbE/yOJxbM295bQ/s800/code_flow.jpeg" height="712" width="800" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 3 High Level Perspective of OS code&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;使用ljmp指令由真實模式轉換至32位元保護模式 (Ring 0)。其片段程式碼如下所示:&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;  /* Jump to protected-mode OS code        *&lt;br /&gt;   * ljmpl prototype:                      *&lt;br /&gt;   *   ljmpl segment_selector_of_CS offset */&lt;br /&gt;  ljmpl     $SegSelectorCode32, $0&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;此區段程式碼將Msg1輸出至螢幕，並將LDT的segment selector載入至LDTR，接著使用lcall指令跳至LDT的CS，如下所示:&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;    /* Load LDT selector */&lt;br /&gt;   mov     $(SegSelectorLDT), %ax&lt;br /&gt;&lt;br /&gt;   /* Load LDT selector in GDT to LDT register */&lt;br /&gt;   lldt     %ax&lt;br /&gt;&lt;br /&gt;   /* Jump to code segment in LDT */&lt;br /&gt;   lcall     $(SegSelectorLDTCode32), $0&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;如第1點所述。&lt;/li&gt;&lt;li&gt;如第1點所述。&lt;/li&gt;&lt;li&gt;輸出Msg2，隨即使用lret指令返回LABEL_GDT_CODE。&lt;/li&gt;&lt;li&gt;通常，call與ret指令必須配合使用。執行call指令時，處理器會將SS、ESP、CS與EIP推入(Push) 該執行空間的堆疊 (Stack)。接著，執行ret指令時，處理器會將EIP、CS、ESP與SS從堆疊取出 (Pop)。為了實現從Ring 0返回Ring 3，底下程式碼模擬處理器的工作: 將Ring 3的SS、ESP、CS與EIP推入(Push) 該執行空間的堆疊 (Stack)並使用lret指令返回Ring 3。&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;   pushl    $(SegSelectorStackR3)&lt;br /&gt;  pushl    $(TopOfStackR3)&lt;br /&gt;  pushl    $(SegSelectorCodeR3)&lt;br /&gt;  pushl    $0&lt;br /&gt;  lret&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;從Ring 0 (LABEL_GDT_CODE)返回 Ring 3 (LABEL_GDT_CODE_R3)。&lt;/li&gt;&lt;li&gt;此Ring 3程式區段將Msg1_R3輸出至螢幕，利用call gate並搭配TSS成功地返回Ring 0程式區段。因此，必須設定TSS之ESP0與SS0欄位，如下所示:&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;LABEL_TSS:&lt;br /&gt; .4byte  0                         /* Previous Task Link   */&lt;br /&gt; .4byte  TopOfStackR0              /* ESP0                 */&lt;br /&gt; .4byte  SegSelectorStackR0        /* SS0                  */&lt;br /&gt; .4byte  0                         /* ESP1                 */&lt;br /&gt; .4byte  0                         /* SS1                  */&lt;br /&gt; .4byte  0                         /* ESP2                 */&lt;br /&gt; .4byte  0                         /* SS2                  */&lt;br /&gt; .4byte  0                         /* CR3 (PDBR)           */&lt;br /&gt; .4byte  0                         /* EIP                  */&lt;br /&gt; .4byte  0                         /* EFLAGS               */&lt;br /&gt; .4byte  0                         /* EAX                  */&lt;br /&gt; .4byte  0                         /* ECX                  */&lt;br /&gt; .4byte  0                         /* EDX                  */&lt;br /&gt; .4byte  0                         /* EBX                  */&lt;br /&gt; .4byte  0                         /* ESP                  */&lt;br /&gt; .4byte  0                         /* EBP                  */&lt;br /&gt; .4byte  0                         /* ESI                  */&lt;br /&gt; .4byte  0                         /* EDI                  */&lt;br /&gt; .4byte  0                         /* ES                   */&lt;br /&gt; .4byte  0                         /* CS                   */&lt;br /&gt; .4byte  0                         /* SS                   */&lt;br /&gt; .4byte  0                         /* DS                   */&lt;br /&gt; .4byte  0                         /* FS                   */&lt;br /&gt; .4byte  0                         /* GS                   */&lt;br /&gt; .4byte  0                         /* LDT Segment Selector */&lt;br /&gt; .2byte  0                         /* Reserved             */&lt;br /&gt; .2byte  (. - LABEL_TSS + 2)       /* I/O Map Base Address */&lt;br /&gt;.set TSSLen, (. - LABEL_TSS)&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;在此，特別對特權等級轉換做進一步解釋，以便讓讀者了解為什麼只要設定ESP0與SS0欄位即可。當存取目的程式區段 (Destination Code Segment)是被允許的，處理器便會根據Call Gate Descriptor的Segment Selector欄位找出對應的程式區段，如果又涉及特權等級轉換，處理器會將原本使用中的堆疊切換至目標特權等級的堆疊。舉例來說，假設目前程式區段運行於Ring 3，處理器便使用Ring 3的堆疊，當使用Call Gate欲轉換至Ring 0的程式區段。如果此要求是被允許的，則處理器會跳至Ring 0的程式區段並使用Ring 0的堆疊，因此程式設計員必須先設定Ring 0堆疊 (ESP0與SS0)，這就是為什麼必須設定TSS的ESP與SS0欄位的原因。 &lt;/li&gt;&lt;li&gt;跳至GDT之Call Gate的描述子 (Descriptor)。&lt;/li&gt;&lt;li&gt;根據Call Gate描述子的Segment Selector欄位找出對應的CS。&lt;/li&gt;&lt;li&gt;將Msg3輸出至螢幕並返回。&lt;/li&gt;&lt;li&gt;返回Ring 3程式區段，並執行一無窮迴圈。&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span &gt;&lt;span style="font-weight: bold;"&gt;QEMU測試結果&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/IBsFbmqxad6PDGiLFgtiRQ?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_VP7dWGNif7M/TRRZP4uXGGI/AAAAAAAACbI/g1Q7njx1sIw/s640/result.jpeg" height="356" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;【Reference】&lt;br /&gt;[1] &lt;a href="http://share.solrex.org/WriteOS/index_cht.html"&gt;Solrex - 使用開源軟體-自己動手寫作業系統&lt;/a&gt;&lt;br /&gt;[2] &lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBUQhgIwAA&amp;amp;url=http%3A%2F%2Fwww.intel.com%2FAssets%2Fja_JP%2FPDF%2Fmanual%2F253668.pdf&amp;amp;ei=8e2jTM7TLorEvQOAsrynDQ&amp;amp;usg=AFQjCNGQ-LN-fJMj1hQhxGaiDArpzKB15Q&amp;amp;sig2=Q0bhLPtu2mgT6V18u9XWBw"&gt;Intel 64 and &lt;em&gt;IA&lt;/em&gt;-&lt;em&gt;32&lt;/em&gt; Architectures. Software &lt;em&gt;Developer's Manual&lt;/em&gt;. &lt;em&gt;Volume  3A&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://goods.ruten.com.tw/item/show?21003267617319"&gt;30天打造OS！作業系統自作入門&lt;/a&gt;&lt;br /&gt;[4] &lt;a href="http://blog.linux.org.tw/~jserv/archives/002031.html"&gt;Jserv's Blog&lt;/a&gt;&lt;br /&gt;[5] &lt;a href="http://www.cs.nctu.edu.tw/~huangmc/works/web/Boot_x86/Boot_x86.html"&gt;&lt;span class="titledown"&gt;X86 開機流程小記&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;[6] &lt;span style="font-size: 100%;"&gt;&lt;a href="http://www.ibm.com/developerworks/library/l-gas-nasm.html"&gt;Linux assemblers: A comparison of GAS and NASM&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;[7] linux-source-2.6.31&lt;div&gt;[8] &lt;a href="http://hpds.ee.ncku.edu.tw/~adrian/blog_archive/os_dev/pe-call-gate-tss.tar.gz"&gt;本篇範例下載點&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-8408852371468883905?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/8408852371468883905/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=8408852371468883905' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8408852371468883905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8408852371468883905'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/12/gnu-assembler-call-gatetss-task-state.html' title='[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (七) 利用Call Gate與TSS (Task-State Segment)實現特權等級的轉換'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_VP7dWGNif7M/TRQTHjxHviI/AAAAAAAACak/PX2sd_MTkC4/s72-c/structure_of_a_task.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-6513691312005326130</id><published>2010-12-08T16:22:00.010+08:00</published><updated>2010-12-09T11:14:41.198+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boot loader'/><category scheme='http://www.blogger.com/atom/ns#' term='GDT'/><category scheme='http://www.blogger.com/atom/ns#' term='call gate'/><category scheme='http://www.blogger.com/atom/ns#' term='segment selector'/><category scheme='http://www.blogger.com/atom/ns#' term='protected-mode'/><category scheme='http://www.blogger.com/atom/ns#' term='operating system (OS)'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU Assembler (GAS)'/><category scheme='http://www.blogger.com/atom/ns#' term='real-mode'/><category scheme='http://www.blogger.com/atom/ns#' term='LDT'/><title type='text'>[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (六) 簡介Call Gate</title><content type='html'>Call Gate主要目的用來將一程式的特權等級 (Privilege Level) 轉換至另一個特權等級。舉例來說，Linux使用者利用ioctl()系統呼叫從user space (Privilege 3)進入kernel space (Privilege 0)。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Note&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;本篇範例程式僅示範如何使用call gate，並如何利用call gate呼叫所對應的程式碼片段，所有的程式碼都運行於privilege 0。對於特權等級的轉換 (Privilege 3 -&gt; Privilege 0)，留待往後的文章再詳加探討。本篇文章僅簡單地介紹Call Gate，詳盡介紹請參考&lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBUQhgIwAA&amp;amp;url=http%3A%2F%2Fwww.intel.com%2FAssets%2Fja_JP%2FPDF%2Fmanual%2F253668.pdf&amp;amp;ei=8e2jTM7TLorEvQOAsrynDQ&amp;amp;usg=AFQjCNGQ-LN-fJMj1hQhxGaiDArpzKB15Q&amp;amp;sig2=Q0bhLPtu2mgT6V18u9XWBw"&gt;Intel 64 and &lt;em&gt;IA&lt;/em&gt;-&lt;em&gt;32&lt;/em&gt; Architectures. Software &lt;em&gt;Developer's Manual&lt;/em&gt;. &lt;em&gt;Volume  3A&lt;/em&gt;&lt;/a&gt;之5.8節。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Call-Gate Descriptor之介紹&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;參考Figure 1，其欄位如下所述:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Offset: 代表所指定的程式區段 (Code Segment)進入點 (Entry Point)，通常都設為0。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Segment Selector: 此區段選擇器指定所要存取的程式區段 (Code Segment)。如此說明或許有點模糊，請參考Figure 2，此圖紅色數字方塊展示出設定Call Gate的必要程序，因此設定Call Gate需要三道步驟：A. 設定Call Gate Descriptor相關欄位，其欄位設定值如Table 1所示。B. 設定對應之程式區段。C. 設定Call-Gate之區段選擇器。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Param. Count: 指定呼叫程序 (Calling Procedure)欲傳遞幾個參數給被呼叫的程序 (Called Procedure)。&lt;/li&gt;&lt;li&gt;DPL (Descriptor Privilege Level): 此區段描述子之特權等級，其DPL與RPL特權等級之檢查請參考&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBUQhgIwAA&amp;amp;url=http%3A%2F%2Fwww.intel.com%2FAssets%2Fja_JP%2FPDF%2Fmanual%2F253668.pdf&amp;amp;ei=8e2jTM7TLorEvQOAsrynDQ&amp;amp;usg=AFQjCNGQ-LN-fJMj1hQhxGaiDArpzKB15Q&amp;amp;sig2=Q0bhLPtu2mgT6V18u9XWBw"&gt;Intel 64 and &lt;em&gt;IA&lt;/em&gt;-&lt;em&gt;32&lt;/em&gt; Architectures. Software &lt;em&gt;Developer's Manual&lt;/em&gt;. &lt;em&gt;Volume  3A&lt;/em&gt;&lt;/a&gt;之Figure 5-11。&lt;/li&gt;&lt;li&gt;P: 此Call-Gate描述子是否有有效 (有效: P=1, 無效: P=0)。&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/HBTCCZm5QCOCiLTtmzzAZA?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_VP7dWGNif7M/TP9FJNsiB_I/AAAAAAAACS0/SH4fGMdw0I8/s640/call-gate-desc.jpeg" height="230" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 1. Call-Gate Descriptor&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/yJUpJUSZL6f-3h4pfmFKHQ?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_VP7dWGNif7M/TQA_lmve1PI/AAAAAAAACTE/inbhWbc8toY/s640/call-gate-conf.jpeg" height="454" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 2. Steps for Configuring Call Gate&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/2IASxYH_N20UKHdNEWdnvw?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_VP7dWGNif7M/TQA_l5Sq8kI/AAAAAAAACTI/Oy-bkGxamEQ/s400/call-gate-desc-filed-cfg.jpeg" height="195" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Table 1. Field Value Configuration for Call-Gate Descriptor&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Boot Loader程式碼&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;請參考&lt;a href="http://adrianhuang.blogspot.com/2010/09/gnu-assembler-16-real-mode-32-protect.html"&gt;此篇文章&lt;/a&gt;的"Boot Loader 程式碼"。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;作業系統程式碼&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Figure 3為作業系統程式碼，此作業系統程式碼運行於32位元保護模式，程式說明如下:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;定義七個Segment Descriptor (LABEL_GDT_NULL、LABEL_GDT_CODE、LABEL_GDT_DATA、LABEL_GDT_VIDEO、LABEL_GDT_LDT、LABEL_GDT_CG_CODE與LABEL_GDT_CG)。其中VIDEO的基底位址為0xB8000，詳情請參考&lt;a href="http://wiki.osdev.org/Printing_to_Screen"&gt;Printing to Screen&lt;/a&gt;。接著定義GDT的長度、定義Code、Data、VIDEO與LDT的segment selector、定義輸出的字串、定義GDTPtr與定義LDT表。&lt;/li&gt;&lt;li&gt;LABEL_GDT_CG為Call Gate Descriptor，其儲存在GDT。此設定步驟為Figure 2的1號紅色方塊。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;LABEL_GDT_CG_CODE為Call Gate Descriptor欄位Segment Selector所指定的地方，也就是Call Gate所對應的區段程式碼。此設定步驟為Figure 2的2號紅色方塊。&lt;/li&gt;&lt;/ol&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* os.S&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;#include "pm.h"&lt;br /&gt;&lt;br /&gt;.code16&lt;br /&gt;.text&lt;br /&gt;  jmp os_main&lt;br /&gt;&lt;br /&gt;# Segment descritors for GDT&lt;br /&gt;LABEL_GDT_NULL:     SEG_DESC     0, 0, 0&lt;br /&gt;LABEL_GDT_CODE:     SEG_DESC     0, (PECode32Len - 1), (DESC_ATTR_TYPE_CD_ER | DESC_ATTR_D)&lt;br /&gt;LABEL_GDT_DATA:     SEG_DESC     0, (DataLen - 1), (DESC_ATTR_TYPE_CD_RW)&lt;br /&gt;LABEL_GDT_VIDEO:    SEG_DESC     0xB8000, 0xFFFF, (DESC_ATTR_TYPE_CD_RW)&lt;br /&gt;LABEL_GDT_LDT:      SEG_DESC     0, (LDTLen - 1), (DESC_ATTR_TYPE_LDT)&lt;br /&gt;LABEL_GDT_CG_CODE:  SEG_DESC     0, (CG_CODE32_LEN - 1), (DESC_ATTR_TYPE_CD_ER | DESC_ATTR_D)&lt;br /&gt;LABEL_GDT_CG:       CALL_GATE    SegSelectorCGCODE, 0, 0, (GATE_CG_ATTR)&lt;br /&gt;&lt;br /&gt;# The length of GDT&lt;br /&gt;.set GdtLen, (. - LABEL_GDT_NULL)&lt;br /&gt;&lt;br /&gt;# Segment selectors&lt;br /&gt;.set SegSelectorCode32,   (LABEL_GDT_CODE - LABEL_GDT_NULL)&lt;br /&gt;.set SegSelectorData,     (LABEL_GDT_DATA - LABEL_GDT_NULL)&lt;br /&gt;.set SegSelectorVideo,    (LABEL_GDT_VIDEO - LABEL_GDT_NULL)&lt;br /&gt;.set SegSelectorLDT,      (LABEL_GDT_LDT - LABEL_GDT_NULL)&lt;br /&gt;.set SegSelectorCGCODE,   (LABEL_GDT_CG_CODE - LABEL_GDT_NULL)&lt;br /&gt;.set SegSelectorCG,       (LABEL_GDT_CG - LABEL_GDT_NULL)&lt;br /&gt;&lt;br /&gt;# data segment&lt;br /&gt;LABEL_DATA:&lt;br /&gt;Msg1:     .ascii "Welcome to Protect mode in GDT.\0"&lt;br /&gt;Msg2:     .ascii "Welcome to Protect mode in LDT.\0"&lt;br /&gt;Msg3:     .ascii "Welcome to Protect mode through Call Gate.\0"&lt;br /&gt;&lt;br /&gt;.set     Msg1Offset, (Msg1 - LABEL_DATA)&lt;br /&gt;.set     Msg2Offset, (Msg2 - LABEL_DATA)&lt;br /&gt;.set     Msg3Offset, (Msg3 - LABEL_DATA)&lt;br /&gt;&lt;br /&gt;.set DataLen, (. - LABEL_DATA)&lt;br /&gt;&lt;br /&gt;# GDTR pointer&lt;br /&gt;LABEL_GDTR:&lt;br /&gt;  .2byte (GdtLen - 1)     # Limit field&lt;br /&gt;  .4byte 0                 # base field&lt;br /&gt;&lt;br /&gt;# LDT information&lt;br /&gt;LABEL_LDT:&lt;br /&gt;LABEL_LDT_ENTRY: SEG_DESC 0, (LDT_CODE32_LEN - 1), (DESC_ATTR_TYPE_CD_E | DESC_ATTR_D)&lt;br /&gt;&lt;br /&gt;# length of LDT&lt;br /&gt;.set LDTLen, (. - LABEL_LDT)&lt;br /&gt;&lt;br /&gt;# LDT selector&lt;br /&gt;.set SegSelectorLDTCode32,     (LABEL_LDT_ENTRY - LABEL_LDT + SA_TIL)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# real-mode OS code&lt;br /&gt;os_main:&lt;br /&gt;  mov %cs, %ax&lt;br /&gt;  mov %ax, %ds&lt;br /&gt;  mov %ax, %ss&lt;br /&gt;  mov %ax, %es&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* Set gdt for code segment */&lt;br /&gt;  InitSegDescriptor LABEL_PE_CODE32, LABEL_GDT_CODE&lt;br /&gt;  InitSegDescriptor LABEL_DATA, LABEL_GDT_DATA&lt;br /&gt;  InitSegDescriptor LABEL_LDT, LABEL_GDT_LDT&lt;br /&gt;  InitSegDescriptor LABEL_PE_LDT_CODE32, LABEL_LDT_ENTRY&lt;br /&gt;  InitSegDescriptor LABEL_PE_CG_CODE32, LABEL_GDT_CG_CODE&lt;br /&gt;&lt;br /&gt;  /* Set GDTR */&lt;br /&gt;  xor     %ax, %ax&lt;br /&gt;  mov     %cs, %ax&lt;br /&gt;  shl     $4, %eax&lt;br /&gt;  addl    $LABEL_GDT_NULL, %eax&lt;br /&gt;  movl     %eax, (LABEL_GDTR + 2)             &lt;br /&gt;&lt;br /&gt;  /* Enable A20 line */&lt;br /&gt;  xor     %ax, %ax&lt;br /&gt;  in      $0x92, %al&lt;br /&gt;  or      $2, %al&lt;br /&gt;  out     %al, $0x92&lt;br /&gt;&lt;br /&gt;  cli&lt;br /&gt;&lt;br /&gt;  /* Load the GDT base address and limit from memory into the GDTR register */&lt;br /&gt;  lgdt     LABEL_GDTR&lt;br /&gt;&lt;br /&gt;  /* Enable protect mode */&lt;br /&gt;  movl     %cr0, %eax&lt;br /&gt;  orl      $1, %eax&lt;br /&gt;  movl     %eax, %cr0&lt;br /&gt;&lt;br /&gt;  /* Jump to protected-mode OS code */&lt;br /&gt;  ljmp     $SegSelectorCode32, $0&lt;br /&gt;&lt;br /&gt;LABEL_PE_CG_CODE32:&lt;br /&gt;.code32&lt;br /&gt;  mov     $(SegSelectorData), %ax&lt;br /&gt;  mov     %ax, %ds&lt;br /&gt;  mov     $(SegSelectorVideo), %ax&lt;br /&gt;  mov     %ax, %gs&lt;br /&gt;&lt;br /&gt;  xorl    %esi, %esi&lt;br /&gt;  xorl    %edi, %edi&lt;br /&gt;  movl    $Msg3Offset, %esi&lt;br /&gt;  movl    $((80 * 11 + 0) * 2), %edi&lt;br /&gt;  movb    $0xC, %ah&lt;br /&gt;&lt;br /&gt;cg_dump_str:&lt;br /&gt;  lodsb&lt;br /&gt;  andb    %al, %al&lt;br /&gt;  jz      cg_fin&lt;br /&gt;  mov     %ax, %gs:(%edi) &lt;br /&gt;  addl    $2, %edi&lt;br /&gt;  jmp     cg_dump_str&lt;br /&gt;&lt;br /&gt;cg_fin:&lt;br /&gt;  lret &lt;br /&gt;&lt;br /&gt;.set CG_CODE32_LEN, (. - LABEL_PE_CG_CODE32)&lt;br /&gt;&lt;br /&gt;LABEL_PE_LDT_CODE32:&lt;br /&gt;.code32&lt;br /&gt;  # invoke a procedure call throught a call-gate.&lt;br /&gt;  lcall   $(SegSelectorCG), $0&lt;br /&gt;&lt;br /&gt;  mov     $(SegSelectorData), %ax&lt;br /&gt;  mov     %ax, %ds&lt;br /&gt;  mov     $(SegSelectorVideo), %ax&lt;br /&gt;  mov     %ax, %gs&lt;br /&gt;&lt;br /&gt;  xorl    %esi, %esi&lt;br /&gt;  xorl    %edi, %edi&lt;br /&gt;  movl    $Msg2Offset, %esi&lt;br /&gt;  movl    $((80 * 13 + 0) * 2), %edi&lt;br /&gt;  movb    $0xC, %ah&lt;br /&gt;&lt;br /&gt;ldt_dump_str:&lt;br /&gt;  lodsb&lt;br /&gt;  andb    %al, %al&lt;br /&gt;  jz      ldt_fin&lt;br /&gt;  mov     %ax, %gs:(%edi) &lt;br /&gt;  addl    $2, %edi&lt;br /&gt;  jmp     ldt_dump_str&lt;br /&gt;&lt;br /&gt;ldt_fin:&lt;br /&gt;  jmp     .&lt;br /&gt;&lt;br /&gt;.set LDT_CODE32_LEN, (. - LABEL_PE_LDT_CODE32)&lt;br /&gt;&lt;br /&gt;# protected-mode OS code in GDT&lt;br /&gt;LABEL_PE_CODE32:&lt;br /&gt;.code32 &lt;br /&gt;  /* Load data segment selector */&lt;br /&gt;  mov     $(SegSelectorData), %ax&lt;br /&gt;  mov     %ax, %ds&lt;br /&gt;&lt;br /&gt;  /* Load Video segment selector */&lt;br /&gt;  mov     $(SegSelectorVideo), %ax&lt;br /&gt;  mov     %ax, %gs&lt;br /&gt;&lt;br /&gt;  /* Output the data */&lt;br /&gt;  xorl    %esi, %esi&lt;br /&gt;  xorl    %edi, %edi&lt;br /&gt;  movl    $Msg1Offset, %esi&lt;br /&gt;  movl    $((80 * 10 + 0) * 2), %edi&lt;br /&gt;  movb    $0xC, %ah&lt;br /&gt;&lt;br /&gt;dump_str:&lt;br /&gt;  lodsb&lt;br /&gt;  andb    %al, %al&lt;br /&gt;  jz      fin&lt;br /&gt;  mov     %ax, %gs:(%edi) &lt;br /&gt;  addl    $2, %edi&lt;br /&gt;  jmp     dump_str&lt;br /&gt;&lt;br /&gt;fin:&lt;br /&gt;  /* Load LDT selector */&lt;br /&gt;  mov     $(SegSelectorLDT), %ax&lt;br /&gt;&lt;br /&gt;  /* Load LDT selector in GDT to LDT register */&lt;br /&gt;  lldt    %ax&lt;br /&gt;&lt;br /&gt;  /* Jump to code segment in LDT */&lt;br /&gt;  ljmp    $(SegSelectorLDTCode32), $0&lt;br /&gt;&lt;br /&gt;.set PECode32Len, (. - LABEL_PE_CODE32)&lt;br /&gt;   &lt;br /&gt;  .ascii "Welcome to OS context!"&lt;br /&gt;  .byte   0 &lt;br /&gt;&lt;br /&gt;  .org    0x400, 0x41 # fill characters with 'A'. Sector 2&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 3. Operating System Code&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;pm.h標頭檔&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* pm.h&lt;br /&gt;*&lt;br /&gt;* Adrian Huang (adrianhuang0701@gmail.com)&lt;br /&gt;*/&lt;br /&gt;.macro SEG_DESC Base, Limit, Attr&lt;br /&gt;   .2byte (\Limit &amp;amp; 0xFFFF)&lt;br /&gt;   .2byte (\Base &amp;amp; 0xFFFF)&lt;br /&gt;   .byte  ((\Base &amp;gt;&amp;gt; 16) &amp;amp; 0xFF)&lt;br /&gt;   .2byte ((\Attr &amp;amp; 0xF0FF) | ((\Limit &amp;gt;&amp;gt; 8) &amp;amp; 0x0F00))&lt;br /&gt;   .byte  ((\Base &amp;gt;&amp;gt; 24) &amp;amp; 0xFF)&lt;br /&gt;.endm&lt;br /&gt;&lt;br /&gt;.macro InitSegDescriptor OFFSET GDT_SEG_ADDR&lt;br /&gt;  xor     %ax, %ax&lt;br /&gt;  mov     %cs, %ax&lt;br /&gt;  shl     $4, %eax&lt;br /&gt;  addl    $(\OFFSET), %eax&lt;br /&gt;  movw    %ax, (\GDT_SEG_ADDR + 2)&lt;br /&gt;  shr     $16, %eax&lt;br /&gt;  movb    %al, (\GDT_SEG_ADDR + 4) &lt;br /&gt;  movb    %ah, (\GDT_SEG_ADDR + 7) &lt;br /&gt;&lt;br /&gt;.endm&lt;br /&gt;&lt;br /&gt;.macro CALL_GATE SegSelector, Offset, ParamCount, Attr&lt;br /&gt;  .2byte (\Offset &amp;amp; 0xFFFF)&lt;br /&gt;  .2byte (\SegSelector)&lt;br /&gt;  .byte  (\ParamCount)&lt;br /&gt;  .byte  (\Attr)&lt;br /&gt;  .2byte ((\Offset &amp;gt;&amp;gt; 16) &amp;amp; 0xFFFF)&lt;br /&gt;.endm&lt;br /&gt;&lt;br /&gt;.set DESC_ATTR_TYPE_LDT,         0x82     /* LDT Segment         */&lt;br /&gt;.set DESC_ATTR_TYPE_CG,          0x8C     /* Call-Gate Segment         */&lt;br /&gt;.set DESC_ATTR_TYPE_CD_ER,       0x9A     /* Code segment with Execute/Read */&lt;br /&gt;.set DESC_ATTR_TYPE_CD_E,        0x98     /* Code segment with Execute Only */&lt;br /&gt;.set DESC_ATTR_TYPE_CD_RW,       0x92     /* Data segment with R/W         */&lt;br /&gt;.set DESC_ATTR_D,                0x4000   /* 32-bit segment                 */&lt;br /&gt;&lt;br /&gt;/* Selector Attribute */&lt;br /&gt;.set SA_TIL,      0x4&lt;br /&gt;.set SA_RPL0,     0x0&lt;br /&gt;.set SA_RPL1,     0x1&lt;br /&gt;.set SA_RPL2,     0x2&lt;br /&gt;.set SA_RPL3,     0x3&lt;br /&gt;&lt;br /&gt;/* The attribute of call gate */&lt;br /&gt;.set GATE_CG_ATTR, 0x8C&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;編譯程式碼&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;下圖為編譯的Makefile。&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;LD=ld&lt;br /&gt;CC=gcc&lt;br /&gt;&lt;br /&gt;all: boot_loader.bin&lt;br /&gt;&lt;br /&gt;boot_loader.bin: boot_loader.o os.o&lt;br /&gt;  ${LD} -Ttext=0x7C00 -s $&lt; -o $@ --oformat binary    ${LD} -Ttext=0x0 -s os.o -o os.bin --oformat binary    cat os.bin &gt;&gt; $@&lt;br /&gt;&lt;br /&gt;boot_loader.o:&lt;br /&gt;  ${CC} -c boot_loader.S&lt;br /&gt;&lt;br /&gt;os.o:&lt;br /&gt;  ${CC} -c os.S&lt;br /&gt;&lt;br /&gt;clean:&lt;br /&gt;  rm -f boot_loader.o os.o os.bin boot_loader.bin&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;其編譯訊息如下所示:&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;adrian@adrian-desktop:~/working/build_os/my_ex/blog/pe-call-gate-same-priv$ make clean all&lt;br /&gt;rm -f boot_loader.o os.o os.bin boot_loader.bin  &lt;br /&gt;gcc -c boot_loader.S&lt;br /&gt;gcc -c os.S&lt;br /&gt;ld -Ttext=0x7C00 -s boot_loader.o -o boot_loader.bin --oformat binary&lt;br /&gt;ld -Ttext=0x0 -s os.o -o os.bin --oformat binary&lt;br /&gt;ld: warning: cannot find entry symbol _start; defaulting to 0000000000000000&lt;br /&gt;cat os.bin &amp;gt;&amp;gt; boot_loader.bin&lt;br /&gt;adrian@adrian-desktop:~/working/build_os/my_ex/blog/pe-call-gate-same-priv$&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;QEMU測試結果&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/BrgMRX8ZUUPMymP_tNrPqg?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_VP7dWGNif7M/TQBGZwLTqrI/AAAAAAAACTQ/4nVf2VyAhLs/s640/call-gate-result.jpeg" height="299" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;[1] &lt;a href="http://share.solrex.org/WriteOS/index_cht.html"&gt;Solrex - 使用開源軟體-自己動手寫作業系統&lt;/a&gt;&lt;br /&gt;[2] &lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBUQhgIwAA&amp;amp;url=http%3A%2F%2Fwww.intel.com%2FAssets%2Fja_JP%2FPDF%2Fmanual%2F253668.pdf&amp;amp;ei=8e2jTM7TLorEvQOAsrynDQ&amp;amp;usg=AFQjCNGQ-LN-fJMj1hQhxGaiDArpzKB15Q&amp;amp;sig2=Q0bhLPtu2mgT6V18u9XWBw"&gt;Intel 64 and &lt;em&gt;IA&lt;/em&gt;-&lt;em&gt;32&lt;/em&gt; Architectures. Software &lt;em&gt;Developer's Manual&lt;/em&gt;. &lt;em&gt;Volume  3A&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://goods.ruten.com.tw/item/show?21003267617319"&gt;30天打造OS！作業系統自作入門&lt;/a&gt;&lt;br /&gt;[4] &lt;a href="http://blog.linux.org.tw/%7Ejserv/archives/002031.html"&gt;Jserv's Blog&lt;/a&gt;&lt;br /&gt;[5] &lt;a href="http://www.cs.nctu.edu.tw/%7Ehuangmc/works/web/Boot_x86/Boot_x86.html"&gt;&lt;span class="titledown"&gt;X86 開機流程小記&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;[6] &lt;span style="font-size:100%;"&gt;&lt;a href="http://www.ibm.com/developerworks/library/l-gas-nasm.html"&gt;Linux assemblers: A comparison of GAS and NASM&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;[7] linux-source-2.6.31&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-6513691312005326130?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/6513691312005326130/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=6513691312005326130' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6513691312005326130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6513691312005326130'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/12/gnu-assembler-call-gate.html' title='[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (六) 簡介Call Gate'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_VP7dWGNif7M/TP9FJNsiB_I/AAAAAAAACS0/SH4fGMdw0I8/s72-c/call-gate-desc.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-6058199278159448148</id><published>2010-11-02T14:06:00.001+08:00</published><updated>2010-11-02T14:21:13.432+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='most popular Linux distribution'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Distribution'/><title type='text'>現今最受歡迎的Linux Distribution</title><content type='html'>今天在網路上看到很有興趣的Linux Distribution搜尋排名比較，請參考&lt;a href="http://steamingopencup.blogspot.com/2010/11/what-is-todays-most-popular-linux.html"&gt;原文網址&lt;/a&gt;，其中&lt;a href="http://distrowatch.com/"&gt;DistroWatch&lt;/a&gt;根據使用者點閱Linux Distribution網頁所得出的結果如下:&lt;br /&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;1. Ubuntu&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;2. Fedora&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;3. Mint&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;4. OpenSUSE&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;5. Debian&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;6. PCLinuxOS&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;7. Mandriva&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;8. Sabayon&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;9. Arch&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"&gt;10. Puppy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;然而，此統計數據以Linux Desktop OS Distribution為基礎，所以Android沒在排名之中。&lt;br /&gt;&lt;br /&gt;於是，作者利用Google Trend所得出的結果，則是Android排名第一。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-6058199278159448148?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/6058199278159448148/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=6058199278159448148' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6058199278159448148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6058199278159448148'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/11/linux-distribution.html' title='現今最受歡迎的Linux Distribution'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-5493987994948091223</id><published>2010-10-11T14:39:00.005+08:00</published><updated>2010-10-16T16:34:36.355+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boot loader'/><category scheme='http://www.blogger.com/atom/ns#' term='GDT'/><category scheme='http://www.blogger.com/atom/ns#' term='segment selector'/><category scheme='http://www.blogger.com/atom/ns#' term='protected-mode'/><category scheme='http://www.blogger.com/atom/ns#' term='operating system (OS)'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU Assembler (GAS)'/><category scheme='http://www.blogger.com/atom/ns#' term='real-mode'/><category scheme='http://www.blogger.com/atom/ns#' term='LDT'/><title type='text'>[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (五) 使用Local Descriptor Table (LDT)</title><content type='html'>&lt;a href="http://adrianhuang.blogspot.com/2010/09/gnu-assembler-16-real-mode-32-protect.html"&gt;上篇文章&lt;/a&gt;使用Global Descriptor Table (GDT)儲存Code Segment (CS)與Data Segment (DS)的資訊，以便能在保護模式下成功地執行程式碼與存取資料。本篇說明如何設定LDT，以便能執行位於LDT的程式碼。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;LDT之介紹&lt;/span&gt;&lt;br /&gt;LDT實現作業系統多個程序功能 (multiple processes)，其特色為各個程序有自己的位址空間彼此互不干擾，每個程序會有各自的LDT，當作業系統欲執行某一程序時，作業系統會找出其對應的LDT，以便能執行該程序。詳細資料請參考&lt;a href="http://en.wikipedia.org/wiki/Local_Descriptor_Table"&gt;Local Descriptor Table&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;LDT相關設定&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;LDT設定分成兩大步驟如下所述:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. 在GDT表裡設定一個LDT entry  (Configure a LDT Entry in GDT)&lt;/span&gt;&lt;br /&gt; 參考Figure 1，其每個欄位所應設定值如Table 1所示:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/8ZJZkR1svLR34qstWqRyfg?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_VP7dWGNif7M/TKPnKk2Yx8I/AAAAAAAACQU/JNoCqV5YfPM/s800/seg_descriptor.jpeg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 1. Segment Descriptor&lt;br /&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/jsM4CsSPbU1sLo2DfqBj5Q?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_VP7dWGNif7M/TLLSgvULSNI/AAAAAAAACQ4/1ztjBaGU2W4/s800/LDT_entry.jpeg" height="341" width="387" /&gt;&lt;/a&gt;&lt;br /&gt;Table 1. LDT entry configuration in GDT&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;2. 設定LDT表&lt;/span&gt;&lt;br /&gt;LDT表設定code segment/data segment相關資訊，其設定值如Table 2所示。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/qa24NgEK9j8Sp7-8iw1A4g?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_VP7dWGNif7M/TLLSghRqYEI/AAAAAAAACQ8/ypo7_uUZfo4/s800/LDT_table.jpeg" height="341" width="641" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;Table 2. LDT entry configuration in LDT&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Boot Loader程式碼&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;請參考&lt;a href="http://adrianhuang.blogspot.com/2010/09/gnu-assembler-16-real-mode-32-protect.html"&gt;上篇文章&lt;/a&gt;的"Boot Loader 程式碼"。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;作業系統程式碼&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Figure 2為作業系統程式碼，此作業系統程式碼運行於32位元保護模式，一開始定義三個Segment Descriptor (NULL、CODE32、VIDEO與LDT)，其中VIDEO的基底位址為0xB8000，詳情請參考&lt;a href="http://wiki.osdev.org/Printing_to_Screen"&gt;Printing to Screen&lt;/a&gt;。接著定義GDT的長度、定義Code32、Data、VIDEO與LDT的segment selector、定義輸出的字串、定義GDTPtr與定義LDT表。&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* os.S&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;#include "pm.h"&lt;br /&gt;&lt;br /&gt;.code16&lt;br /&gt;.text&lt;br /&gt;  jmp os_main&lt;br /&gt;&lt;br /&gt;# Segment descritors for GDT&lt;br /&gt;LABEL_GDT_NULL: SEG_DESC 0, 0, 0&lt;br /&gt;LABEL_GDT_CODE: SEG_DESC 0, (PECode32Len - 1), (DESC_ATTR_TYPE_CD_ER | DESC_ATTR_D)&lt;br /&gt;LABEL_GDT_DATA: SEG_DESC 0, (DataLen - 1), (DESC_ATTR_TYPE_CD_RW)&lt;br /&gt;LABEL_GDT_VIDEO: SEG_DESC 0xB8000, 0xFFFF, (DESC_ATTR_TYPE_CD_RW)&lt;br /&gt;LABEL_GDT_LDT: SEG_DESC     0, (LDTLen -1), (DESC_ATTR_TYPE_LDT)&lt;br /&gt;&lt;br /&gt;# The length of GDT&lt;br /&gt;.set GdtLen, (. - LABEL_GDT_NULL)&lt;br /&gt;&lt;br /&gt;# Segment selectors&lt;br /&gt;.set SegSelectorCode32, (LABEL_GDT_CODE - LABEL_GDT_NULL)&lt;br /&gt;.set SegSelectorData,     (LABEL_GDT_DATA - LABEL_GDT_NULL)&lt;br /&gt;.set SegSelectorVideo,     (LABEL_GDT_VIDEO - LABEL_GDT_NULL)&lt;br /&gt;.set SegSelectorLDT,     (LABEL_GDT_LDT - LABEL_GDT_NULL)&lt;br /&gt;&lt;br /&gt;# data segment&lt;br /&gt;LABEL_DATA:&lt;br /&gt;Msg1:     .ascii "Welcome to Protect mode in GDT.\0"&lt;br /&gt;Msg2:     .ascii "Welcome to Protect mode in LDT.\0"&lt;br /&gt;Msg3:     .ascii "This is signed by Adrian.\0"&lt;br /&gt;&lt;br /&gt;.set     Msg1Offset, (Msg1 - LABEL_DATA)&lt;br /&gt;.set     Msg2Offset, (Msg2 - LABEL_DATA)&lt;br /&gt;.set     Msg3Offset, (Msg3 - LABEL_DATA)&lt;br /&gt;&lt;br /&gt;.set DataLen, (. - LABEL_DATA)&lt;br /&gt;&lt;br /&gt;# GDTR pointer&lt;br /&gt;LABEL_GDTR:&lt;br /&gt;  .2byte (GdtLen - 1)     # Limit field&lt;br /&gt;  .4byte 0                 # base field&lt;br /&gt;&lt;br /&gt;# LDT information&lt;br /&gt;LABEL_LDT:&lt;br /&gt;LABEL_LDT_ENTRY: SEG_DESC 0, (LDT_CODE32_LEN - 1), (DESC_ATTR_TYPE_CD_E | DESC_ATTR_D)&lt;br /&gt;&lt;br /&gt;# length of LDT&lt;br /&gt;.set LDTLen, (. - LABEL_LDT)&lt;br /&gt;&lt;br /&gt;# LDT selector&lt;br /&gt;.set SegSelectorLDTCode32,     (LABEL_LDT_ENTRY - LABEL_LDT + SA_TIL)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# real-mode OS code&lt;br /&gt;os_main:&lt;br /&gt;  mov %cs, %ax&lt;br /&gt;  mov %ax, %ds&lt;br /&gt;  mov %ax, %ss&lt;br /&gt;  mov %ax, %es&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  /* Set gdt for code segment */&lt;br /&gt;  InitSegDescriptor LABEL_PE_CODE32, LABEL_GDT_CODE&lt;br /&gt;  InitSegDescriptor LABEL_DATA, LABEL_GDT_DATA&lt;br /&gt;  InitSegDescriptor LABEL_LDT, LABEL_GDT_LDT&lt;br /&gt;  InitSegDescriptor LABEL_PE_LDT_CODE32, LABEL_LDT_ENTRY&lt;br /&gt;&lt;br /&gt;  /* Set GDTR */&lt;br /&gt;  xor     %ax, %ax&lt;br /&gt;  mov     %cs, %ax&lt;br /&gt;  shl     $4, %eax&lt;br /&gt;  addl    $LABEL_GDT_NULL, %eax&lt;br /&gt;  movl     %eax, (LABEL_GDTR + 2)             &lt;br /&gt;&lt;br /&gt;  /* Enable A20 line */&lt;br /&gt;  xor     %ax, %ax&lt;br /&gt;  in         $0x92, %al&lt;br /&gt;  or         $2, %al&lt;br /&gt;  out     %al, $0x92&lt;br /&gt;&lt;br /&gt;  cli&lt;br /&gt;&lt;br /&gt;  /* Load the GDT base address and limit from memory into the GDTR register */&lt;br /&gt;  lgdt     LABEL_GDTR&lt;br /&gt;&lt;br /&gt;   /* Enable protect mode */&lt;br /&gt;  movl     %cr0, %eax&lt;br /&gt;  orl     $1, %eax&lt;br /&gt;  movl     %eax, %cr0&lt;br /&gt;&lt;br /&gt;  /* Jump to protected-mode OS code */&lt;br /&gt;  ljmp     $SegSelectorCode32, $0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;LABEL_PE_LDT_CODE32:&lt;br /&gt;.code32&lt;br /&gt;  mov     $(SegSelectorData), %ax&lt;br /&gt;  mov     %ax, %ds&lt;br /&gt;  mov     $(SegSelectorVideo), %ax&lt;br /&gt;  mov     %ax, %gs&lt;br /&gt;&lt;br /&gt;  xorl     %esi, %esi&lt;br /&gt;  xorl    %edi, %edi&lt;br /&gt;  movl     $Msg2Offset, %esi&lt;br /&gt;  movl     $((80 * 11 + 0) * 2), %edi&lt;br /&gt;  movb     $0xC, %ah&lt;br /&gt;&lt;br /&gt;ldt_dump_str:&lt;br /&gt;  lodsb&lt;br /&gt;  andb     %al, %al&lt;br /&gt;  jz      ldt_fin&lt;br /&gt;  mov     %ax, %gs:(%edi) &lt;br /&gt;  addl     $2, %edi&lt;br /&gt;  jmp     ldt_dump_str&lt;br /&gt;&lt;br /&gt;ldt_fin:&lt;br /&gt;  jmp .&lt;br /&gt;&lt;br /&gt;.set LDT_CODE32_LEN, (. - LABEL_PE_LDT_CODE32)&lt;br /&gt;&lt;br /&gt;# protected-mode OS code in GDT&lt;br /&gt;LABEL_PE_CODE32:&lt;br /&gt;.code32 &lt;br /&gt;  /* Load data segment selector */&lt;br /&gt;  mov     $(SegSelectorData), %ax&lt;br /&gt;  mov     %ax, %ds&lt;br /&gt;&lt;br /&gt;  /* Load Video segment selector */&lt;br /&gt;  mov     $(SegSelectorVideo), %ax&lt;br /&gt;  mov     %ax, %gs&lt;br /&gt;&lt;br /&gt;  /* Output the data */&lt;br /&gt;  xorl     %esi, %esi&lt;br /&gt;  xorl    %edi, %edi&lt;br /&gt;  movl     $Msg1Offset, %esi&lt;br /&gt;  movl     $((80 * 10 + 0) * 2), %edi&lt;br /&gt;  movb     $0xC, %ah&lt;br /&gt;&lt;br /&gt;dump_str:&lt;br /&gt;  lodsb&lt;br /&gt;  andb     %al, %al&lt;br /&gt;  jz      fin&lt;br /&gt;  mov     %ax, %gs:(%edi) &lt;br /&gt;  addl     $2, %edi&lt;br /&gt;  jmp     dump_str&lt;br /&gt;&lt;br /&gt;fin:&lt;br /&gt;  /* Load LDT selector */&lt;br /&gt;  mov     $(SegSelectorLDT), %ax&lt;br /&gt;&lt;br /&gt;  /* Load LDT selector in GDT to LDT register */&lt;br /&gt;  lldt     %ax&lt;br /&gt;&lt;br /&gt;  /* Jump to code segment in LDT */&lt;br /&gt;  ljmp     $(SegSelectorLDTCode32), $0&lt;br /&gt;&lt;br /&gt;.set PECode32Len, (. - LABEL_PE_CODE32)&lt;br /&gt;   &lt;br /&gt;os_msg:&lt;br /&gt;  .ascii "Welcome to OS context!"&lt;br /&gt;  .byte     0 &lt;br /&gt;&lt;br /&gt;  .org    0x200, 0x41 # fill characters with 'A'. Sector 2&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 2. Code for Operating System &lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;16位元real mode程式碼 (os_main)中，執行若干任務如下所述:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;設定LABEL_GDT_CODE的基底位址為PE_CODE32的起始位址&lt;/li&gt;&lt;li&gt;設定LABEL_GDT_DATA的基底位址為LABEL_DATA的起始位址&lt;/li&gt;&lt;li&gt;設定LABEL_GDT_LDT的基底位址為LABEL_LDT的起始位址&lt;/li&gt;&lt;li&gt;設定LABEL_LDT_ENTRY的基底位址為LABEL_PE_LDT_CODE32的起始位址&lt;/li&gt;&lt;li&gt;設定GDTPtr的基底位址為GDT的起始位址(也就是GDT_DESC_NULL)&lt;/li&gt;&lt;li&gt;開啟A20線路 (&lt;a href="http://en.wikipedia.org/wiki/A20_line"&gt;A20 Line&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;將GDT的起始位址載入至GDTR暫存器&lt;/li&gt;&lt;li&gt;設定cr0暫存器的bit 0以便進入保護模式&lt;/li&gt;&lt;li&gt;使用ljmp指令跳至PE_CODE32程式碼&lt;/li&gt;&lt;li&gt;使用lldt指令將LDT的segment selector載入至LDTR (Local Descriptor Table Register)，並跳至SegSelectorLDTCode32 segment selector執行LDT的程式碼。&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;32位元保護模式程式碼 (LABEL_PE_CODE32)利用Video segment selector將"Welcome to Protect mode in GDT."顯示在螢幕上，而LABEL_PE_LDT_CODE32則將"Welcome to Protect mode in LDT."顯示在螢幕上，用以驗證程式運作之正確性。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;pm.h標頭檔&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* pm.h&lt;br /&gt;*&lt;br /&gt;* Adrian Huang (adrianhuang0701@gmail.com)&lt;br /&gt;*/&lt;br /&gt;.macro SEG_DESC Base, Limit, Attr&lt;br /&gt;   .2byte (\Limit &amp;amp; 0xFFFF)&lt;br /&gt;  .2byte (\Base &amp;amp; 0xFFFF)&lt;br /&gt;  .byte  ((\Base &amp;gt;&amp;gt; 16) &amp;amp; 0xFF)&lt;br /&gt;  .2byte ((\Attr &amp;amp; 0xF0FF) | ((\Limit &amp;gt;&amp;gt; 8) &amp;amp; 0x0F00))&lt;br /&gt;  .byte  ((\Base &amp;gt;&amp;gt; 24) &amp;amp; 0xFF)&lt;br /&gt;.endm&lt;br /&gt;&lt;br /&gt;.macro InitSegDescriptor OFFSET GDT_SEG_ADDR&lt;br /&gt;  xor     %ax, %ax&lt;br /&gt;  mov     %cs, %ax&lt;br /&gt;  shl     $4, %eax&lt;br /&gt;  addl    $(\OFFSET), %eax&lt;br /&gt;  movw     %ax, (\GDT_SEG_ADDR + 2)&lt;br /&gt;  shr     $16, %eax&lt;br /&gt;  movb     %al, (\GDT_SEG_ADDR + 4) &lt;br /&gt;  movb     %ah, (\GDT_SEG_ADDR + 7) &lt;br /&gt;&lt;br /&gt;.endm&lt;br /&gt;&lt;br /&gt;.set DESC_ATTR_TYPE_LDT,         0x82       /* LDT Segment         */&lt;br /&gt;.set DESC_ATTR_TYPE_CD_ER,         0x9A     /* Code segment with Execute/Read */&lt;br /&gt;.set DESC_ATTR_TYPE_CD_E,         0x98     /* Code segment with Execute Only */&lt;br /&gt;.set DESC_ATTR_TYPE_CD_RW,         0x92    /* Data segment with R/W         */&lt;br /&gt;.set DESC_ATTR_D,                 0x4000     /* 32-bit segment                 */&lt;br /&gt;&lt;br /&gt;/* Selector Attribute */&lt;br /&gt;.set SA_TIL,     0x4&lt;br /&gt;.set SA_RPL0,     0x0&lt;br /&gt;.set SA_RPL1,     0x1&lt;br /&gt;.set SA_RPL2,     0x2&lt;br /&gt;.set SA_RPL3,     0x3&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;編譯程式碼&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;請參照&lt;a href="http://adrianhuang.blogspot.com/2010/09/gnu-assembler-16-real-mode-32-protect.html"&gt;此篇的Makefile程式碼&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;其編譯訊息如下所示:  &lt;/span&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;adrian@adrian-desktop:~/working/build_os/my_ex/04day/blog/pe-multi-seg-ldt$ make clean all&lt;br /&gt;rm -f boot_loader.o os.o boot_loader.bin  &lt;br /&gt;gcc -c boot_loader.S&lt;br /&gt;gcc -c os.S&lt;br /&gt;ld -Ttext=0x7C00 -s boot_loader.o -o boot_loader.bin --oformat binary&lt;br /&gt;ld -Ttext=0x0 -s os.o -o os.bin --oformat binary&lt;br /&gt;ld: warning: cannot find entry symbol _start; defaulting to 0000000000000000&lt;br /&gt;cat os.bin &amp;gt;&amp;gt; boot_loader.bin&lt;br /&gt;adrian@adrian-desktop:~/working/build_os/my_ex/04day/blog/pe-multi-seg-ldt$&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;QEMU測試結果&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/PKDzQF_7U46K4exASKbHpQ?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_VP7dWGNif7M/TLLSg4i24UI/AAAAAAAACRA/jCoO9-m8TVQ/s800/qemu_result.jpeg" height="356" width="800" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;【Reference】&lt;br /&gt;[1] &lt;a href="http://share.solrex.org/WriteOS/index_cht.html"&gt;Solrex - 使用開源軟體-自己動手寫作業系統&lt;/a&gt;&lt;br /&gt;[2] &lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBUQhgIwAA&amp;amp;url=http%3A%2F%2Fwww.intel.com%2FAssets%2Fja_JP%2FPDF%2Fmanual%2F253668.pdf&amp;amp;ei=8e2jTM7TLorEvQOAsrynDQ&amp;amp;usg=AFQjCNGQ-LN-fJMj1hQhxGaiDArpzKB15Q&amp;amp;sig2=Q0bhLPtu2mgT6V18u9XWBw"&gt;Intel 64 and &lt;em&gt;IA&lt;/em&gt;-&lt;em&gt;32&lt;/em&gt; Architectures. Software &lt;em&gt;Developer's Manual&lt;/em&gt;. &lt;em&gt;Volume  3A&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://goods.ruten.com.tw/item/show?21003267617319"&gt;30天打造OS！作業系統自作入門&lt;/a&gt;&lt;br /&gt;[4] &lt;a href="http://blog.linux.org.tw/%7Ejserv/archives/002031.html"&gt;Jserv's Blog&lt;/a&gt;&lt;br /&gt;[5] &lt;a href="http://www.cs.nctu.edu.tw/%7Ehuangmc/works/web/Boot_x86/Boot_x86.html"&gt;&lt;span class="titledown"&gt;X86 開機流程小記&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;[6] &lt;span style="font-size:100%;"&gt;&lt;a href="http://www.ibm.com/developerworks/library/l-gas-nasm.html"&gt;Linux assemblers: A comparison of GAS and NASM&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;[7] linux-source-2.6.31&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-5493987994948091223?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/5493987994948091223/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=5493987994948091223' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5493987994948091223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5493987994948091223'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/10/gnu-assembler-local-descriptor-table.html' title='[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (五) 使用Local Descriptor Table (LDT)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_VP7dWGNif7M/TKPnKk2Yx8I/AAAAAAAACQU/JNoCqV5YfPM/s72-c/seg_descriptor.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-6541016701809094622</id><published>2010-09-29T19:02:00.011+08:00</published><updated>2010-12-13T16:31:28.124+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boot loader'/><category scheme='http://www.blogger.com/atom/ns#' term='GDT'/><category scheme='http://www.blogger.com/atom/ns#' term='segment selector'/><category scheme='http://www.blogger.com/atom/ns#' term='protected-mode'/><category scheme='http://www.blogger.com/atom/ns#' term='operating system (OS)'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU Assembler (GAS)'/><category scheme='http://www.blogger.com/atom/ns#' term='real-mode'/><title type='text'>[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (四) 由16位元真實模式 (Real Mode) 進入32位元保護模式 (Protect Mode)</title><content type='html'>前三篇文章所展示的程式碼都是CPU執行於真實模式 (Real Mode)。然而，一般作業系統運行於保護模式 (Protect Mode)，其記憶體定址最高可至4GB (32位元)。故本文先介紹real mode與protect mode記憶體定址的方式。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Real mode與Protect mode記憶體定址介紹&lt;/span&gt;&lt;br /&gt;Figure 1展示real mode記憶體定址方式，其觀念在於將邏輯位址(Logical Address)的區段(Segment)位址向左位移4個位元，再將其所得的位址加上位移值，如此便能轉換成線性位址 (Linear Address)。至於，邏輯位址該如何表示呢? 其表示法為"Address of Segment:Offset"&lt;br /&gt;，例如: CS:IP、SS:SP、DS:SI和ES:DI，詳情請參考x86 Assembly Language。Figure 1描述一個簡單邏輯位址轉換線性位址的例子，因此不再贅述。&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/6MQCPa-j_5ALgP2MdVg6Jw?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_VP7dWGNif7M/TKPjAlBIZWI/AAAAAAAACQI/0ntQ8lJeA_4/s800/real_mode_mem_seg.jpeg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 1. Memory Segmentation in Real Mode&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Figure 2展示保護模式記憶體定址方式，其觀念在於將區段 (Segment)看成區段選擇器 (Segment Selector)，用此選擇器索引出對應的Segment Descriptor，如此便能索引32位元的基底位址 (32-bit base address)，然後再加上位移植，便能轉換成線性位址。&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/R-5X61JdsmFTKMJEfMg-Gg?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_VP7dWGNif7M/TKPjAl-PopI/AAAAAAAACQE/0FYUt4MeSwM/s800/protected_mode_mem_seg.jpeg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 2. Memory Segment in Protect Mode&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;保護模式相關課題之介紹 &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;此段落將著重介紹保護模式相關課題之介紹，包含介紹GDT/LDT (GDTR/LDTR)、Segment Descriptor、Segment Selector、 和Memory Management Register&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Global and Local Descriptor Table (GDT and LDT)&lt;br /&gt;&lt;/span&gt;當CPU運行於保護模式時，所有的記憶體存取都必須經由GDT或LDT，此表格 (GDT or LDT)存放最小單元便是Segment Descriptor。每一個Segment Descriptor都有對應的segment selector，用以索引出對應的Segment Descriptor。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;GDTR and LDTR (GDT Register and LDT Register)&lt;/span&gt;&lt;br /&gt;GDTR與LDTR用以儲存GDT與LDT的起始位置，此設定必須在進入保護模式完成設定。Figure 3展示GDTR與LDTR格式，其中GDTR包含32位元的基底位址與16位元的長度限制。而LDTR多增加了16位元的segment selector。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/Zd6XSETuPnDLSlCg4Btviw?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_VP7dWGNif7M/TKPnKthT2cI/AAAAAAAACQY/ix5IKym5mtg/s800/mem_mgmt_reg.jpeg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 3. Memory Management Register&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;Segment Descriptor&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Segment Descriptor為Descriptor Table組成的基本元素，其長度為8位元組。如Figure 4所示，可分為三大類: 1. 32位元的基底位址 (Base Address), 2. 20位元的區段限制 (Segment Limit), 3. 區段屬性。細節請參考&lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBUQhgIwAA&amp;amp;url=http%3A%2F%2Fwww.intel.com%2FAssets%2Fja_JP%2FPDF%2Fmanual%2F253668.pdf&amp;amp;ei=8e2jTM7TLorEvQOAsrynDQ&amp;amp;usg=AFQjCNGQ-LN-fJMj1hQhxGaiDArpzKB15Q&amp;amp;sig2=Q0bhLPtu2mgT6V18u9XWBw"&gt;Intel 64 and &lt;em&gt;IA&lt;/em&gt;-&lt;em&gt;32&lt;/em&gt; Architectures. Software &lt;em&gt;Developer's Manual&lt;/em&gt;. &lt;em&gt;Volume  3A&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/8ZJZkR1svLR34qstWqRyfg?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_VP7dWGNif7M/TKPnKk2Yx8I/AAAAAAAACQU/JNoCqV5YfPM/s800/seg_descriptor.jpeg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Figure 4. Segment Descriptor [2]&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Segment Selector&lt;/span&gt;&lt;br /&gt;Figure 5展示Segment Selector示意圖，其目的用來索引對應的Segment Descriptor。因Descriptor Index有13個位元，故Descriptor個數最大可至8192。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/3-Imq7RuximxRb6bxVHbXQ?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_VP7dWGNif7M/TKPnKpXs6kI/AAAAAAAACQQ/GcmMK1YE4RM/s800/seg_selector.jpeg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold;"&gt;Figure 5. Segment Selector&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Boot Loader程式碼&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* boot_loader.S&lt;br /&gt;*&lt;br /&gt;* Copyright (C) 2010 Adrian Huang (adrianhuang0701@gmail.com)&lt;br /&gt;*&lt;br /&gt;* This code is intended to simulate a simplified boot loader. This boot&lt;br /&gt;* loader loads 3 sectors into the physical memory and jumps the entry&lt;br /&gt;* point of OS.&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;.code16&lt;br /&gt;&lt;/code&gt;&lt;code&gt;.text&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;code&gt;.set     BOOT_SEG,     0x07C0    /* starting code segment (CS) of boot loader */&lt;br /&gt;.set     OS_SEG,       0x0900    /* code segment address of OS entry point */&lt;br /&gt;.set     OS_OFFSET,    0x0000    /* the offset address of OS entry point */&lt;br /&gt;&lt;br /&gt;.global _start&lt;br /&gt;_start:&lt;br /&gt;  # FAT12 file system format&lt;br /&gt; jmp       start_prog         # jmp instruction&lt;br /&gt;&lt;br /&gt;.byte     0x90&lt;br /&gt;.ascii    "ADRIAN  "         # OEM name (8 bytes)&lt;br /&gt;.word     512                # Bytes per sector&lt;br /&gt;.byte     1                  # Sector per cluster&lt;br /&gt;.word     1                  # Reserved sector count: should be 1 for FAT12&lt;br /&gt;.byte     2                  # Number of file allocation tables.&lt;br /&gt;.word     224                # Maximum number of root directory entries.&lt;br /&gt;.word     2880               # Total sectors&lt;br /&gt;.byte     0xf0               # Media descriptor:&lt;br /&gt;.word     9                  # Sectors per File Allocation Table&lt;br /&gt;.word     18                 # Sectors per track&lt;br /&gt;.word     2                  # Number of heads&lt;br /&gt;.long     0                  # Count of hidden sectors&lt;br /&gt;.long     0                  # Total sectors&lt;br /&gt;.byte     0                  # Physical driver number&lt;br /&gt;.byte     0                  # Reserved&lt;br /&gt;.byte     0x29               # Extended boot signature&lt;br /&gt;.long     0x12345678         # Serial Number&lt;br /&gt;.ascii    "HELLO-OS   "      # Volume Label&lt;br /&gt;.ascii    "FAT12   "         # FAT file system type&lt;br /&gt;.fill     18, 1, 0           # fill 18 characters with zero&lt;br /&gt;&lt;br /&gt;start_prog:&lt;br /&gt;# initialize the register with cs register&lt;br /&gt;movw    %cs, %ax&lt;br /&gt;movw    %ax, %ds&lt;br /&gt;movw    %ax, %es&lt;br /&gt;movw    %ax, %ss&lt;br /&gt;xorw    %sp, %sp&lt;br /&gt;&lt;br /&gt;cld                     # clear direction flag&lt;br /&gt;sti                     # set interrupt flag&lt;br /&gt;&lt;br /&gt;# The following code is loaded three sectors (2-4th sectors from boot.bin)&lt;br /&gt;# into the physical memory 0x8000-0x85FF.&lt;br /&gt;movw    $OS_SEG,     %ax&lt;br /&gt;mov     %ax,         %es  # ES:BX-&amp;gt; destination buffer address pointer&lt;br /&gt;movw    $OS_OFFSET,  %bx&lt;br /&gt;movb    $2,          %cl  # sector&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;cont:&lt;br /&gt;movb     $0x02, %ah  # Read sectors from drive&lt;br /&gt;movb     $0x1,  %al  # Sectors to read count&lt;br /&gt;movb     $0x0,  %ch  # track&lt;br /&gt;movb     $0x0,  %dh  # head&lt;br /&gt;movb     $0,    %dl  # drive&lt;br /&gt;&lt;br /&gt;int      $0x13       # trigger a interrupt 0x13 service&lt;br /&gt;jc       fail        # the clear flag is set if the operation is failed&lt;br /&gt;&lt;br /&gt;mov      %es,   %ax&lt;br /&gt;addw     $0x20, %ax  # move to the next sector&lt;br /&gt;movw     %ax,   %es  # move to the next sector&lt;br /&gt;incb     %cl&lt;br /&gt;&lt;br /&gt;cmpb     $3, %cl     # has finished reading 3 sectors?&lt;br /&gt;jbe      cont        # continue to read the sector&lt;br /&gt;&lt;br /&gt;jmp      os_entry    # jump to OS entry point&lt;br /&gt;&lt;br /&gt;fail:&lt;br /&gt;movw     $err_msg, %si&lt;br /&gt;fail_loop:&lt;br /&gt;lodsb&lt;br /&gt;andb     %al, %al&lt;br /&gt;jz       end&lt;br /&gt;movb     $0x0e, %ah&lt;br /&gt;int      $0x10&lt;br /&gt;jmp      fail_loop&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;os_entry:&lt;br /&gt;ljmp $OS_SEG, $OS_OFFSET  # jump to os context&lt;br /&gt;&lt;br /&gt;end:&lt;br /&gt; hlt&lt;br /&gt; jmp end&lt;br /&gt;&lt;br /&gt;err_msg:&lt;br /&gt;.ascii "Reading sectors operation is failed!"&lt;br /&gt;.byte     0&lt;br /&gt;&lt;br /&gt;.org 0x1FE, 0x41 # fill the rest of characters with zero until the 254th character&lt;br /&gt;&lt;br /&gt; # Boot sector signature&lt;br /&gt;.byte     0x55&lt;br /&gt;.byte     0xaa&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;作業系統程式碼&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;此作業系統程式碼運行於32位元保護模式，一開始定義三個Segment Descriptor (NULL, CODE32與VIDEO)，其中VIDEO的基底位址為0xB8000，詳情請參考&lt;a href="http://wiki.osdev.org/Printing_to_Screen"&gt;Printing to Screen&lt;/a&gt;。接著定義GDT的長度、定義Code32與VIDEO的segment selector、定義GDTPtr。&lt;br /&gt;&lt;br /&gt;16位元real mode程式碼 (os_main)中，執行若干任務如下所述:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;設定Code32的基底位址為PE_CODE32的起始位址&lt;/li&gt;&lt;li&gt;設定GDTPtr的基底位址為GDT的起始位址(也就是GDT_DESC_NULL)&lt;/li&gt;&lt;li&gt;開啟A20線路 (&lt;a href="http://en.wikipedia.org/wiki/A20_line"&gt;A20 Line&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;將GDT的起始位址載入至GDTR暫存器&lt;/li&gt;&lt;li&gt;設定cr0暫存器的bit 0以便進入保護模式&lt;/li&gt;&lt;li&gt;使用ljmp指令跳至PE_CODE32程式碼&lt;/li&gt;&lt;/ol&gt;32位元保護模式程式碼 (PE_CODE32)利用Video segment selector將'H'字元顯示在螢幕，用以驗證程式運作之正確性。&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* os.S&lt;br /&gt;*&lt;br /&gt;* Adrian Huang (adrianhuang0701@gmail.com)&lt;br /&gt;*&lt;br /&gt;* This code is OS context for protected-mode.&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;#include "pm.h"&lt;br /&gt;&lt;br /&gt;.code16&lt;br /&gt;.text&lt;br /&gt;jmp os_main&lt;br /&gt;&lt;br /&gt;# Segment descritors for GDT&lt;br /&gt;GDT_DESC_NULL: SEG_DESC      0, 0, 0&lt;br /&gt;GDT_DESC_CODE32: SEG_DESC    0, (PECode32Len - 1), (DESC_ATTR_TYPE_CD_ER | DESC_ATTR_D)&lt;br /&gt;GDT_DESC_VIDEO: SEG_DESC     0xB8000, 0xFFFF, (DESC_ATTR_TYPE_CD_RW)&lt;br /&gt;&lt;br /&gt;# The length of GDT&lt;br /&gt;.set GdtLen, (. - GDT_DESC_NULL)&lt;br /&gt;&lt;br /&gt;# Segment selectors for code segment and video output&lt;br /&gt;.set SegSelectorCode32, (GDT_DESC_CODE32 - GDT_DESC_NULL)&lt;br /&gt;.set SegSelectorVideo,  (GDT_DESC_VIDEO - GDT_DESC_NULL)&lt;br /&gt;&lt;br /&gt;# GDTR pointer&lt;br /&gt;GDTPtr:&lt;br /&gt;.2byte (GdtLen - 1)     # Limit field&lt;br /&gt;.4byte 0                 # base field&lt;br /&gt;&lt;br /&gt;# real-mode OS code&lt;br /&gt;os_main:&lt;br /&gt;mov %cs, %ax&lt;br /&gt;mov %ax, %ds&lt;br /&gt;mov %ax, %ss&lt;br /&gt;mov %ax, %es&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* Set gdt for code segment */&lt;br /&gt;InitSegDescriptor PE_CODE32, GDT_DESC_CODE32&lt;br /&gt;&lt;br /&gt;/* Set GDTR */&lt;br /&gt;xor     %ax, %ax&lt;br /&gt;mov     %cs, %ax&lt;br /&gt;shl     $4, %eax&lt;br /&gt;addl    $GDT_DESC_NULL, %eax&lt;br /&gt;movl     %eax, (GDTPtr + 2)        &lt;br /&gt;&lt;br /&gt;/* Enable A20 line */&lt;br /&gt;xor     %ax,   %ax&lt;br /&gt;in      $0x92, %al&lt;br /&gt;or      $2,    %al&lt;br /&gt;out     %al,   $0x92&lt;br /&gt;&lt;br /&gt;cli&lt;br /&gt;&lt;br /&gt;/* Load the GDT base address and limit from memory into the GDTR register */&lt;br /&gt;lgdt     GDTPtr&lt;br /&gt;&lt;br /&gt;/* Enable protect mode */&lt;br /&gt;movl     %cr0, %eax&lt;br /&gt;orl      $1,   %eax&lt;br /&gt;movl     %eax, %cr0&lt;br /&gt;&lt;br /&gt;/* Jump to protected-mode OS code */&lt;br /&gt;ljmp     $SegSelectorCode32, $0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# protected-mode OS code&lt;br /&gt;PE_CODE32:&lt;br /&gt;.code32&lt;br /&gt;/* Load Video segment selector */&lt;br /&gt;mov     $(SegSelectorVideo), %ax&lt;br /&gt;mov     %ax, %gs&lt;br /&gt;&lt;br /&gt;/* Output the data */&lt;br /&gt;movl    $((80 * 10 + 0) * 2), %edi&lt;br /&gt;movb    $0xC, %ah&lt;br /&gt;movb    $'H', %al&lt;br /&gt;mov     %ax, %gs:(%edi)&lt;br /&gt;&lt;br /&gt;jmp .&lt;br /&gt;&lt;br /&gt;.set PECode32Len, (. - PE_CODE32)&lt;br /&gt;&lt;br /&gt;os_msg:&lt;br /&gt;.ascii "Welcome to OS context!"&lt;br /&gt;.byte     0&lt;br /&gt;&lt;br /&gt;.org    0x200, 0x41 # fill characters with 'A'. Sector 2&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;pm.h標頭檔&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* pm.h&lt;br /&gt;*&lt;br /&gt;* Adrian Huang (adrianhuang0701@gmail.com)&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.macro SEG_DESC Base, Limit, Attr&lt;br /&gt;.2byte (\Limit &amp;amp; 0xFFFF)&lt;br /&gt;.2byte (\Base &amp;amp; 0xFFFF)&lt;br /&gt;.byte  ((\Base &amp;gt;&amp;gt; 16) &amp;amp; 0xFF)&lt;br /&gt;.2byte ((\Attr &amp;amp; 0xF0FF) | ((\Limit &amp;gt;&amp;gt; 8) &amp;amp; 0x0F00))&lt;br /&gt;.byte  ((\Base &amp;gt;&amp;gt; 24) &amp;amp; 0xFF)&lt;br /&gt;.endm&lt;br /&gt;&lt;br /&gt;.macro InitSegDescriptor OFFSET GDT_SEG_ADDR&lt;br /&gt;xor     %ax, %ax&lt;br /&gt;mov     %cs, %ax&lt;br /&gt;shl     $4, %eax&lt;br /&gt;addl    $(\OFFSET), %eax&lt;br /&gt;movw    %ax, (\GDT_SEG_ADDR + 2)&lt;br /&gt;shr     $16, %eax&lt;br /&gt;movb    %al, (\GDT_SEG_ADDR + 4)&lt;br /&gt;movb    %ah, (\GDT_SEG_ADDR + 7)&lt;br /&gt;&lt;br /&gt;.endm&lt;br /&gt;&lt;br /&gt;.set DESC_ATTR_TYPE_LDT,         0x82     /* LDT Segment                    */&lt;br /&gt;.set DESC_ATTR_TYPE_CD_ER,       0x9A     /* Code segment with Execute/Read */&lt;br /&gt;.set DESC_ATTR_TYPE_CD_E,        0x98     /* Code segment with Execute Only */&lt;br /&gt;.set DESC_ATTR_TYPE_CD_RW,       0x92     /* Data segment with R/W          */&lt;br /&gt;.set DESC_ATTR_D,                0x4000   /* 32-bit segment                 */&lt;br /&gt;&lt;br /&gt;/* Selector Attribute */&lt;br /&gt;.set SA_TIL,      0x4&lt;br /&gt;.set SA_RPL0,     0x0&lt;br /&gt;.set SA_RPL1,     0x1&lt;br /&gt;.set SA_RPL2,     0x2&lt;br /&gt;.set SA_RPL3,     0x3&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;編譯程式碼&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;下圖為編譯的Makefile。&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;LD=ld&lt;br /&gt;CC=gcc&lt;br /&gt;&lt;br /&gt;all: boot_loader.bin&lt;br /&gt;&lt;br /&gt;boot_loader.bin: boot_loader.o os.o&lt;br /&gt;${LD} -Ttext=0x7C00 -s $&amp;lt; -o $@ --oformat binary&lt;br /&gt;${LD} -Ttext=0x0 -s os.o -o os.bin --oformat binary&lt;br /&gt;cat os.bin &amp;gt;&amp;gt; $@&lt;br /&gt;&lt;br /&gt;boot_loader.o:&lt;br /&gt;${CC} -c boot_loader.S&lt;br /&gt;&lt;br /&gt;os.o:&lt;br /&gt;${CC} -c os.S&lt;br /&gt;&lt;br /&gt;clean:&lt;br /&gt;rm -f boot_loader.o os.o os.bin boot_loader.bin&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;其編譯訊息如下所示:  &lt;/span&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;adrian@adrian-desktop:~/working/build_os/my_ex/04day/pe-orig-makefile$ make all&lt;br /&gt;gcc -c boot_loader.S&lt;br /&gt;gcc -c os.S&lt;br /&gt;ld -Ttext=0x7C00 -s boot_loader.o -o boot_loader.bin --oformat binary&lt;br /&gt;ld -Ttext=0x0 -s os.o -o os.bin --oformat binary&lt;br /&gt;ld: warning: cannot find entry symbol _start; defaulting to 0000000000000000&lt;br /&gt;cat os.bin &amp;gt;&amp;gt; boot_loader.bin&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;QEMU測試結果&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/h4xkhlHExbFSKDfcf_OWtQ?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_VP7dWGNif7M/TKQ-OzdYlmI/AAAAAAAACQg/4BeXj_eQ3Qw/s800/qemu_result.jpeg" height="312" width="800" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;[1] &lt;a href="http://share.solrex.org/WriteOS/index_cht.html"&gt;Solrex - 使用開源軟體-自己動手寫作業系統&lt;/a&gt;&lt;br /&gt;[2] &lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBUQhgIwAA&amp;amp;url=http%3A%2F%2Fwww.intel.com%2FAssets%2Fja_JP%2FPDF%2Fmanual%2F253668.pdf&amp;amp;ei=8e2jTM7TLorEvQOAsrynDQ&amp;amp;usg=AFQjCNGQ-LN-fJMj1hQhxGaiDArpzKB15Q&amp;amp;sig2=Q0bhLPtu2mgT6V18u9XWBw"&gt;Intel 64 and &lt;em&gt;IA&lt;/em&gt;-&lt;em&gt;32&lt;/em&gt; Architectures. Software &lt;em&gt;Developer's Manual&lt;/em&gt;. &lt;em&gt;Volume  3A&lt;/em&gt;&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://goods.ruten.com.tw/item/show?21003267617319"&gt;30天打造OS！作業系統自作入門&lt;/a&gt;&lt;br /&gt;[4] &lt;a href="http://blog.linux.org.tw/%7Ejserv/archives/002031.html"&gt;Jserv's Blog&lt;/a&gt;&lt;br /&gt;[5] &lt;a href="http://www.cs.nctu.edu.tw/%7Ehuangmc/works/web/Boot_x86/Boot_x86.html"&gt;&lt;span class="titledown"&gt;X86 開機流程小記&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;[6] &lt;span style="font-size:100%;"&gt;&lt;a href="http://www.ibm.com/developerworks/library/l-gas-nasm.html"&gt;Linux assemblers: A comparison of GAS and NASM&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;[7] linux-source-2.6.31&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-6541016701809094622?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/6541016701809094622/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=6541016701809094622' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6541016701809094622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6541016701809094622'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/09/gnu-assembler-16-real-mode-32-protect.html' title='[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (四) 由16位元真實模式 (Real Mode) 進入32位元保護模式 (Protect Mode)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_VP7dWGNif7M/TKPjAlBIZWI/AAAAAAAACQI/0ntQ8lJeA_4/s72-c/real_mode_mem_seg.jpeg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-8850593042898705625</id><published>2010-08-31T18:58:00.005+08:00</published><updated>2010-08-31T20:03:25.593+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boot loader'/><category scheme='http://www.blogger.com/atom/ns#' term='operating system (OS)'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU Assembler (GAS)'/><category scheme='http://www.blogger.com/atom/ns#' term='OS loading'/><title type='text'>[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (三) Boot Loader + 作業系統載入實例 (CF Card)</title><content type='html'>&lt;a href="http://adrianhuang.blogspot.com/2010/08/gnu-assembler-boot-loader.html"&gt;上篇&lt;/a&gt;說明如何撰寫小型Boot Loader將作業系統載入至記憶體並執行該作業系統程式碼，並利用qemu實現。為了更真實性，本篇將boot loader及作業系統安裝在CF card並利用CF card開機，用以證明該boot loader及作業系統可以正確地在實體機器上運行。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;將DL暫存器更改為0x80&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;由於&lt;a href="http://adrianhuang.blogspot.com/2010/08/gnu-assembler-boot-loader.html"&gt;上篇&lt;/a&gt;是使用軟碟機開機，因此在使用BIOS中斷服務0x13時 (AH=02 Read Sectors from Driver)，需將DL暫存器設定為0(0代表軟碟機0，1代表軟碟機1)，但因為現在要從硬碟讀取，所以需將DL設定為0x80，即底下範例程式紅色部份。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Boot Loader範例程式 (以FAT32為範例)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* boot_loader.S&lt;br /&gt;*&lt;br /&gt;* Copyright (C) 2010 Adrian Huang (adrianhuang0701@gmail.com)&lt;br /&gt;*&lt;br /&gt;* This code is intended to simulate a simplified boot loader. This boot&lt;br /&gt;* loader loads 3 sectors into the physical memory and jumps the entry&lt;br /&gt;* point of OS.&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;BOOT_SEG     = 0x07C0    /* starting code segment (CS) of boot loader */&lt;br /&gt;OS_SEG       = 0x0800    /* code segment address of OS entry point */&lt;br /&gt;OS_OFFSET    = 0x0000    /* the offset address of OS entry point */&lt;br /&gt;&lt;br /&gt; .code16&lt;br /&gt;&lt;br /&gt; .section .text&lt;br /&gt;&lt;br /&gt; .global _start&lt;br /&gt;_start:&lt;br /&gt; # FAT12 file system format&lt;br /&gt; ljmp     $BOOT_SEG, $start_prog         # jmp instruction&lt;br /&gt;&lt;br /&gt; .byte     0x90&lt;br /&gt; .ascii    "ADRIAN  "        # OEM name (8 bytes)&lt;br /&gt; .word     512               # Bytes per sector&lt;br /&gt; .byte     1                 # Sector per cluster&lt;br /&gt; .word     32                # Reserved sector count: should be 32 for FAT32&lt;br /&gt; .byte     2                 # Number of file allocation tables. &lt;br /&gt; .word     0                 # Maximum number of root directory entries. 0 for FAT32&lt;br /&gt; .word     0                 # Total sectors&lt;br /&gt; .byte     0xf8              # Media descriptor: fix disk&lt;br /&gt; .word     9                 # Sectors per File Allocation Table&lt;br /&gt; .word     18                # Sectors per track&lt;br /&gt; .word     2                 # Number of heads&lt;br /&gt; .long     0                 # Count of hidden sectors&lt;br /&gt; .long     2030112           # Total sectors&lt;br /&gt; .byte     0                 # Physical driver number&lt;br /&gt; .byte     0                 # Reserved&lt;br /&gt; .byte     0x29              # Extended boot signature&lt;br /&gt; .long     0x12345678        # Serial Number&lt;br /&gt; .ascii    "HELLO-OS   "     # Volume Label&lt;br /&gt; .ascii    "FAT12   "        # FAT file system type&lt;br /&gt; .fill     18, 1, 0          # fill 18 characters with zero&lt;br /&gt;&lt;br /&gt;start_prog:&lt;br /&gt; # initialize the register with cs register&lt;br /&gt; movw    %cs, %ax&lt;br /&gt; movw    %ax, %ds&lt;br /&gt; movw    %ax, %es&lt;br /&gt; movw    %ax, %ss&lt;br /&gt; xorw    %sp, %sp&lt;br /&gt;&lt;br /&gt; cld                     # clear direction flag&lt;br /&gt; sti                     # set interrupt flag&lt;br /&gt;&lt;br /&gt; # The following code is loaded three sectors (2-4th sectors from boot.bin)&lt;br /&gt; # into the physical memory 0x8000-0x85FF.&lt;br /&gt; movw    $OS_SEG,     %ax&lt;br /&gt; mov     %ax,         %es  # ES:BX-&gt; destination buffer address pointer&lt;br /&gt; movb    $2,          %cl  # sector&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;cont:&lt;br /&gt; movw     $0,    %bx&lt;br /&gt; movb     $0x02, %ah  # Read sectors from drive&lt;br /&gt; movb     $0x1,  %al  # Sectors to read count&lt;br /&gt; movb     $0x0,  %ch  # track&lt;br /&gt; movb     $0x0,  %dh  # head&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; movb     $0x80, %dl  # drive&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; int      $0x13        # trigger a interrupt 0x13 service&lt;br /&gt; jc       fail         # the clear flag is set if the operation is failed&lt;br /&gt;&lt;br /&gt; mov      %es, %ax  &lt;br /&gt; addw     $0x20, %ax     # move to the next sector&lt;br /&gt; movw     %ax, %es       # move to the next sector&lt;br /&gt; incb     %cl&lt;br /&gt; cmpb     $3, %cl        # has finished reading 3 sectors?&lt;br /&gt; jbe      cont           # continue to read the sector&lt;br /&gt;&lt;br /&gt; jmp  os_entry           # jump to OS entry point&lt;br /&gt;&lt;br /&gt;fail:&lt;br /&gt; movw     $err_msg, %si&lt;br /&gt;fail_loop:&lt;br /&gt; lodsb &lt;br /&gt; andb     %al, %al&lt;br /&gt; jz       end&lt;br /&gt; movb     $0x0e, %ah&lt;br /&gt; int      $0x10    &lt;br /&gt; jmp      fail_loop&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;os_entry:&lt;br /&gt; ljmp $OS_SEG, $OS_OFFSET  # jump to os context&lt;br /&gt;&lt;br /&gt;end:&lt;br /&gt; hlt&lt;br /&gt;&lt;br /&gt;err_msg:&lt;br /&gt; .ascii "Reading sectors operation is failed!"&lt;br /&gt; .byte     0&lt;br /&gt;&lt;br /&gt; .org 0x1FE, 0x41 # fill the rest of characters with zero until the 254th character&lt;br /&gt;&lt;br /&gt; # Boot sector signature&lt;br /&gt; .byte     0x55&lt;br /&gt; .byte     0xaa&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:130%;"&gt;&lt;b&gt;作業系統程式碼與編譯&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;請參照&lt;a href="http://adrianhuang.blogspot.com/2010/08/gnu-assembler-boot-loader.html"&gt;這篇&lt;/a&gt;的"作業系統程式碼"與&lt;span style="font-size:78%;"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;/span&gt;&lt;/span&gt;"編譯程式碼"。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;安裝boot_loader.bin安裝至CF card&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;adrian@adrian-mem1:~/img$ sudo dd if=./boot_loader.bin of=/dev/sda&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;測試結果&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;將該系統重開並選擇CF Card開機，其畫面如下:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/4944460647/" title="Flickr 上 adrianhuang0701 的 DSC00165"&gt;&lt;img src="http://farm5.static.flickr.com/4138/4944460647_3a59b9dd54_z.jpg" alt="DSC00165" height="480" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;1.&lt;a href="http://goods.ruten.com.tw/item/show?21003267617319"&gt;30天打造OS！作業系統自作入門&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://blog.linux.org.tw/%7Ejserv/archives/002031.html"&gt;Jserv's Blog&lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.cs.nctu.edu.tw/%7Ehuangmc/works/web/Boot_x86/Boot_x86.html"&gt;&lt;span class="titledown"&gt;X86 開機流程小記&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;4.&lt;span style="font-size:100%;"&gt; &lt;a href="http://www.ibm.com/developerworks/library/l-gas-nasm.html"&gt;Linux assemblers: A comparison of GAS and NASM&lt;/a&gt;&lt;br /&gt;5. &lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51); font-size: 100%;"&gt;&lt;span class="Apple-style-span" style="line-height: 20px; font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;linux-source-2.6.31&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-8850593042898705625?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/8850593042898705625/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=8850593042898705625' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8850593042898705625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8850593042898705625'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/08/gnu-assembler-boot-loader-cf-card.html' title='[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (三) Boot Loader + 作業系統載入實例 (CF Card)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4138/4944460647_3a59b9dd54_t.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-7700434531514818501</id><published>2010-08-20T10:43:00.001+08:00</published><updated>2010-08-20T10:47:07.972+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Chrome OS'/><category scheme='http://www.blogger.com/atom/ns#' term='Tablet'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><title type='text'>Google將推出Chrome作業系統的平板電腦</title><content type='html'>Google將與HTC合作，以Google Chrome作業系統開發平板電腦，預計今年11月26發表。&lt;br /&gt;&lt;br /&gt;詳見:&lt;a href="http://itmanagement.earthweb.com/features/article.php/3899401/First-Chrome-OS-Tablet-Set-for-Black-Friday-Debut.htm"&gt;&lt;span style="font-size:85%;"&gt; First Chrome OS Tablet Set for Black Friday Debut&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;文中還提及為什麼不使用Android的原因。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-7700434531514818501?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/7700434531514818501/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=7700434531514818501' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7700434531514818501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7700434531514818501'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/08/googlechrome.html' title='Google將推出Chrome作業系統的平板電腦'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-5887382314901923606</id><published>2010-08-13T10:57:00.003+08:00</published><updated>2010-08-13T13:46:45.284+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Network Processing Improvement'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><title type='text'>Google大神開始對Linux Kernel Source貢獻了</title><content type='html'>Linux 2.6.35有Google大神的程式碼了!! (跪拜0rz......)&lt;br /&gt;其主要提升網路封包處理速度&lt;br /&gt;詳見: &lt;a href="http://www.linuxplanet.com/linuxplanet/reports/7139/1/"&gt;Linux 2.6.35 Includes Speedy Google Code, Less Bloat&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-5887382314901923606?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/5887382314901923606/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=5887382314901923606' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5887382314901923606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5887382314901923606'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/08/googlelinux-kernel-source.html' title='Google大神開始對Linux Kernel Source貢獻了'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-4254814727587554508</id><published>2010-08-11T10:00:00.017+08:00</published><updated>2010-08-31T20:00:23.208+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boot loader'/><category scheme='http://www.blogger.com/atom/ns#' term='operating system (OS)'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU Assembler (GAS)'/><category scheme='http://www.blogger.com/atom/ns#' term='OS loading'/><title type='text'>[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (二) Boot Loader + 作業系統載入實例 (QEMU)</title><content type='html'>繼&lt;a href="http://adrianhuang.blogspot.com/2010/08/gnu-assembler-hello-world.html"&gt;上篇&lt;/a&gt;說明如何撰寫開機Hello World，本篇文章說明如何撰寫簡單的Boot Loader跟一個只會印出訊息的作業系統。&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;b&gt;小型Boot Loader設計概念&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;筆者所撰寫的小型Boot Loader於BIOS開機成功後，會被載入至實體記憶體位址0x7C00並跳至此位址執行boot loader的程式碼，此boot loader程式碼會將作業系統程式碼 (僅三個磁區)，載入實體記憶體位址0x8000並跳至此位址執行作業系統的程式碼，然而此作業系統別無功能，僅會印出簡單的訊息。如此便能模擬一般boot loader載入作業系統的程序。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;圖一為筆者所編譯出來的plain binary file，此程式碼僅有四個磁區 (共2048 bytes)，0x0-0x1ff為boot loader磁區，0x200-0x7ff為作業系統的三個磁區，雖然，真正的作業系統程式碼在0x200-0x3ff，其它兩個磁區僅填入字元'B'與'C'，但筆者還是把這三個磁區稱為作業系統程式碼，因為boot loader會將這三個磁區載入實體記憶體位址0x8000。&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/8p3bHqe8N6QqnGTbg-dSrQ?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_VP7dWGNif7M/TGE5bKfnz8I/AAAAAAAACPA/Pl9WUK3-Yaw/s400/os_bl_bin_img.jpeg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;圖一、Boot  + OS Binary Image Layout&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;圖二為boot loader將作業系統載入實體記憶體位址示意圖，至於為什麼會選擇0x8000開始存放作業系統程式碼，其原因是x86系統規範位址&lt;a href="http://wiki.osdev.org/Memory_Map_%28x86%29"&gt;0x7E00-0x7FFFF為conventional memory&lt;/a&gt;，因此筆者就挑0x8000來存放程式碼。&lt;div&gt;&lt;br /&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/2e_NK3jlrGxbBoYTolLqzw?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_VP7dWGNif7M/TGE5bbrZ3TI/AAAAAAAACPE/_JSWRtVR5kY/s400/os_bl_mem_layout.jpeg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span class="Apple-style-span"&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;圖二、Boot Loader + OS Physical Memory Layout&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;b&gt;Boot Loader程式碼&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;下圖為Boot Loader程式碼，其運作原理在此稍作描述。首先，boot_loader透過.byte、.word、.long跟.ascii等指令將此磁區描述為一個&lt;a href="http://en.wikipedia.org/wiki/File_Allocation_Table"&gt;FAT12檔案系統&lt;/a&gt;。接著，利用&lt;a href="http://en.wikipedia.org/wiki/INT_13"&gt;中斷服務編號0x13&lt;/a&gt;將作業系統的三個磁區讀入0x8000實體記憶體位址。如果讀取失敗的話，則利用&lt;a href="http://en.wikipedia.org/wiki/INT_10"&gt;中斷服務編號0x010&lt;/a&gt;印出錯誤訊息。特別要提出的是，程式碼使用兩次遠程跳躍 (Far Dump)，其原型ljmp code_segment_address, relative_address，例如: ljmp  $BOOT_SEG, $start_prog代表code segment設定為0x07C0加上start_prog標籤的位址，即0x7C00+start_prog位址，此為&lt;a href="http://en.wikipedia.org/wiki/X86_memory_segmentation"&gt;Intel x86 CPU memory segmentation機制&lt;/a&gt;。透過此設定，boot loader程式碼便能正確地在0x7C00位址執行。另一個ljmp，ljmp $OS_SEG, $OS_OFFSET，因為boot loader將作業系統程式碼放在0x8000實體記憶體位址，因此code segment必須設為0x0800，以便讓作業系統程式碼可以正確地執行。&lt;div&gt;&lt;div&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* boot_loader.S&lt;br /&gt;*&lt;br /&gt;* Copyright (C) 2010 Adrian Huang (adrianhuang0701@gmail.com)&lt;br /&gt;*&lt;br /&gt;* This code is intended to simulate a simplified boot loader. This boot&lt;br /&gt;* loader loads 3 sectors into the physical memory and jumps the entry&lt;br /&gt;* point of OS.&lt;br /&gt;*&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;BOOT_SEG     = 0x07C0       /* starting code segment (CS) of boot loader */&lt;br /&gt;OS_SEG       = 0x0800       /* code segment address of OS entry point */&lt;br /&gt;OS_OFFSET    = 0x0000       /* the offset address of OS entry point */&lt;br /&gt;&lt;br /&gt;.code16&lt;br /&gt;&lt;br /&gt;.section .text&lt;br /&gt;&lt;br /&gt;.global _start&lt;br /&gt;_start:&lt;br /&gt;# FAT12 file system format&lt;br /&gt;ljmp     $BOOT_SEG, $start_prog   # jmp instruction&lt;br /&gt;&lt;br /&gt;.byte   0x90&lt;br /&gt;.ascii  "ADRIAN  "                # OEM name (8 bytes)&lt;br /&gt;.word   512                       # Bytes per sector&lt;br /&gt;.byte   1                         # Sector per cluster&lt;br /&gt;.word   1                         # Reserved sector count: should be 1 for FAT12&lt;br /&gt;.byte   2                         # Number of file allocation tables.&lt;br /&gt;.word   224                       # Maximum number of root directory entries.&lt;br /&gt;.word   2880                      # Total sectors&lt;br /&gt;.byte   0xf0                      # Media descriptor&lt;br /&gt;.word   9                         # Sectors per File Allocation Table&lt;br /&gt;.word   18                        # Sectors per track&lt;br /&gt;.word   2                         # Number of heads&lt;br /&gt;.long   0                         # Count of hidden sectors&lt;br /&gt;.long   2880                      # Total sectors: 18 (sectors per track) * 2 (heads) * 80 (sectors) = 2880&lt;br /&gt;.byte   0                         # Physical driver number&lt;br /&gt;.byte   0                         # Reserved&lt;br /&gt;.byte   0x29                      # Extended boot signature&lt;br /&gt;.long   0x12345678                # Serial Number&lt;br /&gt;.ascii  "HELLO-OS   "             # Volume Label&lt;br /&gt;.ascii  "FAT12   "                # FAT file system type&lt;br /&gt;.fill   18, 1, 0                  # fill 18 characters with zero&lt;br /&gt;&lt;br /&gt;start_prog:&lt;br /&gt;# initialize the register with cs register&lt;br /&gt;movw    %cs, %ax&lt;br /&gt;movw    %ax, %ds&lt;br /&gt;movw    %ax, %es&lt;br /&gt;movw    %ax, %ss&lt;br /&gt;xorw    %sp, %sp&lt;br /&gt;&lt;br /&gt;cld                     # clear direction flag&lt;br /&gt;sti                     # set interrupt flag&lt;br /&gt;&lt;br /&gt;# The following code is loaded three sectors (2-4th sectors from boot.bin)&lt;br /&gt;# into the physical memory 0x8000-0x85FF.&lt;br /&gt;movw    $OS_SEG,     %ax&lt;br /&gt;mov     %ax,         %es  # ES:BX-&gt; destination buffer address pointer&lt;br /&gt;movb    $2,          %cl  # sector&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;cont:&lt;br /&gt;movw     $0,    %bx&lt;br /&gt;movb     $0x02, %ah     # Read sectors from drive&lt;br /&gt;movb     $0x1,  %al     # Sectors to read count&lt;br /&gt;movb     $0x0,  %ch     # track&lt;br /&gt;movb     $0x0,  %dh     # head&lt;br /&gt;movb     $0,    %dl     # drive&lt;br /&gt;&lt;br /&gt;int      $0x13          # trigger a interrupt 0x13 service&lt;br /&gt;jc       fail           # the clear flag is set if the operation is failed&lt;br /&gt;&lt;br /&gt;mov     %es, %ax&lt;br /&gt;addw    $0x20, %ax      # move to the next sector&lt;br /&gt;movw    %ax, %es        # move to the next sector&lt;br /&gt;incb    %cl&lt;br /&gt;cmpb    $3, %cl         # has finished reading 3 sectors?&lt;br /&gt;jbe     cont            # continue to read the sector&lt;br /&gt;&lt;br /&gt;jmp  os_entry           # jump to OS entry point&lt;br /&gt;&lt;br /&gt;fail:&lt;br /&gt;movw    $err_msg, %si&lt;br /&gt;fail_loop:&lt;br /&gt;lodsb&lt;br /&gt;andb    %al, %al&lt;br /&gt;jz      end&lt;br /&gt;movb    $0x0e, %ah&lt;br /&gt;int     $0x10&lt;br /&gt;jmp     fail_loop&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;os_entry:&lt;br /&gt;ljmp $OS_SEG, $OS_OFFSET  # jump to os context&lt;br /&gt;&lt;br /&gt;end:&lt;br /&gt;hlt&lt;br /&gt;&lt;br /&gt;err_msg:&lt;br /&gt;.ascii "Reading sectors operation is failed!"&lt;br /&gt;.byte     0&lt;br /&gt;&lt;br /&gt;.org 0x1FE, 0x41 # fill the rest of characters with zero until the 254th character&lt;br /&gt;&lt;br /&gt;# Boot sector signature&lt;br /&gt;.byte     0x55&lt;br /&gt;.byte     0xaa&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;b&gt;作業系統程式碼&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;此段程式碼僅將訊息輸出至螢幕上，所以不再贅述。&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;/* os.S&lt;/code&gt;&lt;div&gt; *  &lt;/div&gt;&lt;div&gt; * Copyright (C) 2010 Adrian Huang (adrianhuang0701@gmail.com)&lt;/div&gt;&lt;div&gt; *&lt;/div&gt;&lt;div&gt; * This code is OS context. &lt;/div&gt;&lt;div&gt; *&lt;/div&gt;&lt;div&gt; */&lt;/div&gt;&lt;div&gt;    .code16&lt;/div&gt;&lt;div&gt;    .section .text&lt;/div&gt;&lt;div&gt;    .global main&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;main:&lt;/div&gt;&lt;div&gt;    movw    %cs, %ax&lt;/div&gt;&lt;div&gt;    movw    %ax, %ds&lt;/div&gt;&lt;div&gt;    movw    %ax, %es&lt;/div&gt;&lt;div&gt;    movw    %ax, %ss&lt;/div&gt;&lt;div&gt;    xorw    %sp, %sp&lt;/div&gt;&lt;div&gt;    &lt;/div&gt;&lt;div&gt;    cld                     # clear direction flag &lt;/div&gt;&lt;div&gt;    sti                     # set interrupt flag&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;    movw  $os_msg, %si&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;load_msg:&lt;/div&gt;&lt;div&gt;    lodsb&lt;/div&gt;&lt;div&gt;    andb %al, %al&lt;/div&gt;&lt;div&gt;    jz      os_fin&lt;/div&gt;&lt;div&gt;    movb $0x0e, %ah&lt;/div&gt;&lt;div&gt;    int  $0x10&lt;/div&gt;&lt;div&gt;    jmp  load_msg&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;os_fin:&lt;/div&gt;&lt;div&gt;    hlt&lt;/div&gt;&lt;div&gt;    jmp  os_fin&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;os_msg:&lt;/div&gt;&lt;div&gt;    .ascii "Welcome to OS context!"&lt;/div&gt;&lt;div&gt;    .byte     0    &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;    .org    0x200, 0x41 # fill characters with 'A'. Sector 1&lt;/div&gt;&lt;div&gt;    .org    0x400, 0x42 # fill characters with 'B'. Sector 2&lt;/div&gt;&lt;div&gt;    .org    0x600, 0x43 # fill characters with 'C'. Sector 3&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/pre&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;編譯程式碼 &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;下圖為編譯的Makefile。&lt;/span&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;LD=ld&lt;/code&gt;&lt;div&gt;CC=gcc&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;all: boot_loader.bin&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;boot_loader.bin: boot_loader.o os.o&lt;/div&gt;&lt;div&gt;    ${LD} -Ttext=0x0 -s $&amp;lt; -o $@ --oformat binary&lt;/div&gt;&lt;div&gt;    ${LD} -Ttext=0x0 -s os.o -o os.bin --oformat binary&lt;/div&gt;&lt;div&gt;    cat os.bin &amp;gt;&amp;gt; $@&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;boot_loader.o:&lt;/div&gt;&lt;div&gt;    ${CC} -c boot_loader.S&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;os.o:&lt;/div&gt;&lt;div&gt;    ${CC} -c os.S&lt;/div&gt;&lt;div&gt;    &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;clean:&lt;/div&gt;&lt;div&gt;    rm -f boot_loader.o boot_loader.bin os.o&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/pre&gt; 其編譯訊息如下所示:  &lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 14px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;adrian@adrian-desktop:~/working/build_os/my_ex/boot_loader$ make clean all&lt;/code&gt;&lt;div&gt;rm -f boot_loader.o boot_loader.bin os.o&lt;/div&gt;&lt;div&gt;gcc -c boot_loader.S&lt;/div&gt;&lt;div&gt;gcc -c os.S&lt;/div&gt;&lt;div&gt;ld -Ttext=0x0 -s boot_loader.o -o boot_loader.bin --oformat binary&lt;/div&gt;&lt;div&gt;ld -Ttext=0x0 -s os.o -o os.bin --oformat binary&lt;/div&gt;&lt;div&gt;ld: warning: cannot find entry symbol _start; defaulting to 0000000000000000&lt;/div&gt;&lt;div&gt;cat os.bin &amp;gt;&amp;gt; boot_loader.bin&lt;/div&gt;&lt;div&gt;adrian@adrian-desktop:~/working/build_os/my_ex/boot_loader$ &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;測試結果&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/QJpSfrQcJAGP1TEYDpqXNw?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_VP7dWGNif7M/TGE5bUAIDOI/AAAAAAAACPI/brWVK2NMEnk/s800/qemu.jpeg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;為了驗證作業系統的程式碼正確地載入實體記憶體位址0x8000，筆者利用xxd工具將boot_loader.bin dump出來，下圖為其結果。紅色框框為作業系統程式碼的十六進制碼。&lt;/div&gt;&lt;div&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/mP8yZuGmO5ZFUiTRoyzxPg?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_VP7dWGNif7M/TGJdT_bHezI/AAAAAAAACPY/ERb56Mrd7js/s800/boot_loader_bin.jpeg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;下圖中，筆者利用qemu提供的xp工具將0x8000-0x8010的內容dump出來，用以跟上圖0x200-0x210比對，比較上、下這兩張圖，可以證明作業系統程式碼正確地被載入至0x8000。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/cRCWjYhThYMjp4QOSsaDmA?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_VP7dWGNif7M/TGJjrKb-jZI/AAAAAAAACPg/6N6r0NKVRCk/s800/qemu_xp.jpeg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51);font-size:100%;" &gt;&lt;span class="Apple-style-span" style="line-height: 20px;font-size:13px;" &gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;【Reference】&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;1.&lt;a href="http://goods.ruten.com.tw/item/show?21003267617319"&gt;30天打造OS！作業系統自作入門&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;2. &lt;a href="http://blog.linux.org.tw/%7Ejserv/archives/002031.html"&gt;Jserv's Blog&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;3. &lt;a href="http://www.cs.nctu.edu.tw/%7Ehuangmc/works/web/Boot_x86/Boot_x86.html"&gt;&lt;span class="titledown"&gt;X86 開機流程小記&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;4.&lt;span style="font-size:100%;"&gt; &lt;a href="http://www.ibm.com/developerworks/library/l-gas-nasm.html"&gt;Linux assemblers: A comparison of GAS and NASM&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;5. linux-source-2.6.31&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-4254814727587554508?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/4254814727587554508/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=4254814727587554508' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4254814727587554508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4254814727587554508'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/08/gnu-assembler-boot-loader.html' title='[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (二) Boot Loader + 作業系統載入實例 (QEMU)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_VP7dWGNif7M/TGE5bKfnz8I/AAAAAAAACPA/Pl9WUK3-Yaw/s72-c/os_bl_bin_img.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-6602070853947775679</id><published>2010-08-03T16:39:00.030+08:00</published><updated>2011-08-23T21:05:36.042+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='operating system (OS)'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='GNU Assembler (GAS)'/><title type='text'>[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (一) 開機Hello World實例</title><content type='html'>小弟最近想嘗試利用GAS(GNU Assembler)組合語言撰寫非常小型的作業系統，本篇文章說明如何利用GAS組合語言在終端機上印出Hello World.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;簡介x86 CPU開機流程&lt;/span&gt;&lt;br /&gt;x86 CPU開機後，首要之事會先跳至0xFFFF0執行BIOS ROM的程式，當BIOS測試程序通過後，BIOS便會把執行權交給下一個程式 (boot loader或一支小程式)，BIOS會將該程式&lt;br /&gt;(通常為一個磁區[Sector]大小，即512 bytes)載入記憶體0x7C00位置，並跳至0x7C00執行該段程式碼。該磁區被稱為MBR，BIOS會檢查該磁區最後兩個位完組必須為0x55AA，否則該磁區該被視為無效的MBR。&lt;br /&gt;&lt;br /&gt;所以，首要之事就是利用GAS撰寫一支大小為512位元組的二進位檔 (Binary File)，此檔需具備底下功能:&lt;ul&gt;&lt;li&gt;檔案系統，如: &lt;a style="font-weight: bold;" href="http://en.wikipedia.org/wiki/File_Allocation_Table"&gt;FAT12&lt;/a&gt;, FAT16, FAT32, NTFS等等。&lt;/li&gt;&lt;li&gt;利用&lt;a style="font-weight: bold;" href="http://en.wikipedia.org/wiki/INT_10"&gt;BIOS中斷號碼0x10&lt;/a&gt;將資料寫至螢幕。&lt;/li&gt;&lt;li&gt;在最後兩個位元組寫入0x55AA以便通過BIOS識別。&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;底下為原始碼:&lt;/span&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;    .code16&lt;br /&gt;&lt;br /&gt;    .section .text&lt;br /&gt;    .global main&lt;br /&gt;main:&lt;br /&gt;    # FAT12 file system format&lt;br /&gt;    jmp       start_prog       # jmp instruction&lt;br /&gt;    .byte     0x90&lt;br /&gt;    .ascii    &amp;quot;ADRIAN  &amp;quot;       # OEM name (8 bytes)&lt;br /&gt;    .word     512              # Bytes per sector&lt;br /&gt;    .byte     1                # Sector per cluster&lt;br /&gt;    .word     1                # Reserved sector count: should be 1 for FAT12&lt;br /&gt;    .byte     2                # Number of file allocation tables.&lt;br /&gt;    .word     224              # Maximum number of root directory entries.&lt;br /&gt;    .word     2880             # Total sectors&lt;br /&gt;    .byte     0xf0             # Media descriptor:&lt;br /&gt;    .word     9                # Sectors per File Allocation Table&lt;br /&gt;    .word     18               # Sectors per track&lt;br /&gt;    .word     2                # Number of heads&lt;br /&gt;    .long     0                # Count of hidden sectors&lt;br /&gt;    .long     2880             # Total sectors: 18 (sectors per track) * 2 (heads) * 80 (sectors) = 2880&lt;br /&gt;    .byte     0                # Physical driver number&lt;br /&gt;    .byte     0                # Reserved&lt;br /&gt;    .byte     0x29             # Extended boot signature&lt;br /&gt;    .long     0x12345678       # Serial Number&lt;br /&gt;    .ascii    &amp;quot;HELLO-OS   &amp;quot;    # Volume Label&lt;br /&gt;    .ascii    &amp;quot;FAT12   &amp;quot;       # FAT file system type&lt;br /&gt;    .fill     18, 1, 0         # fill 18 characters with zero&lt;br /&gt;&lt;br /&gt;start_prog:&lt;br /&gt;    movw    $0, %ax            # Initialize register&lt;br /&gt;    movw    %ax, %ss&lt;br /&gt;    movw    %ax, %ds&lt;br /&gt;    movw    %ax, %es&lt;br /&gt;&lt;br /&gt;    movw    $msg, %si          # move the address of msg to SI&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;loop:&lt;br /&gt;    movb    $0xe, %ah&lt;br /&gt;    movb    (%si), %al        # move the first character of msg to AL register&lt;br /&gt;    cmpb    $0, %al&lt;br /&gt;    je      fin&lt;br /&gt;    int     $0x10             # write the specific character to console&lt;br /&gt;    addw    $1, %si&lt;br /&gt;    jmp     loop&lt;br /&gt;&lt;br /&gt;fin:&lt;br /&gt;# do nothing&lt;br /&gt;&lt;br /&gt;msg:&lt;br /&gt;    .ascii &amp;quot;Hello, World! This is Adrian Huang.&amp;quot;&lt;br /&gt;    .byte   0&lt;br /&gt;&lt;br /&gt;    .org    0x1FE, 0x00       # fill the rest of characters with zero until the 254th character&lt;br /&gt;&lt;br /&gt;# Boot sector signature&lt;br /&gt;    .byte     0x55&lt;br /&gt;    .byte     0xaa&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt; &lt;span style="font-weight: bold;"&gt;Compile and Link&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;以"gcc -c"將.S組合語言轉為成object file&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 12px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;adrian@adrian-desktop:~/working/build_os/my_ex/02day/helloos4$ ls&lt;br /&gt;hello.S&lt;br /&gt;adrian@adrian-desktop:~/working/build_os/my_ex/02day/helloos4$ gcc -c hello.S&lt;br /&gt;adrian@adrian-desktop:~/working/build_os/my_ex/02day/helloos4$ file hello.o&lt;br /&gt;hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped&lt;br /&gt;adrian@adrian-desktop:~/working/build_os/my_ex/02day/helloos4$&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;再經由ld連結器將此object轉換成plain binary file&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 12px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ ld -Ttext=0x7C00 hello.o -o hello.bin --oformat binary&lt;br /&gt;$ file hello.bin&lt;br /&gt;hello.bin: DOS floppy 1440k, x86 hard disk boot sector&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;利用xxd工具觀察helo.bin格式 (以十六進制)&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 12px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;adrian@adrian-desktop:~/working/build_os/my_ex/02day/helloos4$ xxd hello.bin&lt;br /&gt;0000000: eb4e 9041 4452 4941 4e20 2000 0201 0100  .N.ADRIAN  .....&lt;br /&gt;0000010: 02e0 0040 0bf0 0900 1200 0200 0000 0000  ...@............&lt;br /&gt;0000020: 400b 0000 0000 2978 5634 1248 454c 4c4f  @.....)xV4.HELLO&lt;br /&gt;0000030: 2d4f 5320 2020 4641 5431 3220 2020 0000  -OS   FAT12   ..&lt;br /&gt;0000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000050: b800 008e d08e d88e c0be 6b7c b40e 8a04  ..........k|....&lt;br /&gt;0000060: 3c00 7407 cd10 83c6 01eb f148 656c 6c6f  &amp;lt;.t........Hello&lt;br /&gt;0000070: 2c20 576f 726c 6421 2054 6869 7320 6973  , World! This is&lt;br /&gt;0000080: 2041 6472 6961 6e20 4875 616e 672e 0000   Adrian Huang...&lt;br /&gt;0000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00000a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00000d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00000e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00000f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000100: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000110: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000120: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000130: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000140: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000150: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000160: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000170: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000180: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;0000190: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00001a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00001b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00001c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................&lt;br /&gt;00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;接著，使用qemu驗證hello.bin&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/4861596201/" title="Flickr 上 adrianhuang0701 的 qemu"&gt;&lt;img src="http://farm5.static.flickr.com/4135/4861596201_5343a8c136_z.jpg" alt="qemu" height="294" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;為了讓此範例更真實，筆者有一台機器備有CF Card，將hello.bin透過dd工具寫進此CF Card最前面的512 bytes, 命令如下:&lt;br /&gt;&lt;pre style="font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; border: 1px dashed rgb(153, 153, 153); line-height: 12px; padding: 5px; overflow: auto; width: 100%;"&gt;&lt;code&gt;adrian@adrian-mem1:~/img$ sudo dd if=./hello.bin of=/dev/sda&lt;br /&gt;[sudo] password for adrian:&lt;br /&gt;1+0 records in&lt;br /&gt;1+0 records out&lt;br /&gt;512 bytes (512 B) copied, 0.00124243 s, 412 kB/s&lt;br /&gt;adrian@adrian-mem1:~/img$&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;將該系統重開並選擇CF Card開機，其畫面如下:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/4861596195/" title="Flickr 上 adrianhuang0701 的 DSC00153"&gt;&lt;img src="http://farm5.static.flickr.com/4143/4861596195_ed30848882_z.jpg" alt="DSC00153" height="480" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;1.&lt;a href="http://goods.ruten.com.tw/item/show?21003267617319"&gt;30天打造OS！作業系統自作入門&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://blog.linux.org.tw/%7Ejserv/archives/002031.html"&gt;Jserv's Blog&lt;/a&gt;&lt;br /&gt;3. &lt;a href="http://www.cs.nctu.edu.tw/%7Ehuangmc/works/web/Boot_x86/Boot_x86.html"&gt;&lt;span class="titledown"&gt;X86 開機流程小記&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;4.&lt;span style="font-size:100%;"&gt; &lt;a href="http://www.ibm.com/developerworks/library/l-gas-nasm.html"&gt;Linux assemblers: A comparison of GAS and NASM&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-6602070853947775679?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/6602070853947775679/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=6602070853947775679' title='4 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6602070853947775679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6602070853947775679'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/08/gnu-assembler-hello-world.html' title='[打造簡易作業系統 - 以GNU Assembler組合語言撰寫] (一) 開機Hello World實例'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4135/4861596201_5343a8c136_t.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-3088094603806661796</id><published>2010-03-19T11:25:00.002+08:00</published><updated>2010-03-19T11:48:01.370+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Block I/O Layer'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Block I/O Layer I/O Path'/><title type='text'>簡介Linux Block I/O Layer (三) - I/O Path</title><content type='html'>此系列文章最後講解Block I/O Layer I/O Path運作原理。圖一為I/O Path簡易圖，檔案系統核心經由submit_bio函式將該bio交給Block I/O Layer的generic_make_request和__generic_make_request函式，緊接著呼叫__make_request_fn callback函式 (對應至__make_request())，此函式主要目的用來檢查此bio是否可以跟尚未處理的request結構的bio成員結合在一起 (merge)，如果不行的話，則另外配置一個新的request結構並將其bio安插至該reqeust結構，再將該request交給I/O Scheduler，最後Block I/O Layer經由request_fn() callback function將待處理的request交給SCSI子系統。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_VP7dWGNif7M/S6LqemBO5yI/AAAAAAAACMY/Z4j3PCTZADo/s1600-h/generic_block_dev_io_path.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 288px;" src="http://1.bp.blogspot.com/_VP7dWGNif7M/S6LqemBO5yI/AAAAAAAACMY/Z4j3PCTZADo/s320/generic_block_dev_io_path.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5450176310394414882" /&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp圖一、Block I/O Layer之I/O Path簡易圖&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;下圖二為Linux Block I/O Layer核心I/O Path示意圖，此圖以ReiserFS為例，此圖對每個函式有詳細的解釋，所以在此不再解釋，請參照圖二。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_VP7dWGNif7M/S6LwotBWInI/AAAAAAAACMw/-4tU5m8JkeM/s1600-h/block_system_without_iosched.jpeg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 234px;" src="http://1.bp.blogspot.com/_VP7dWGNif7M/S6LwotBWInI/AAAAAAAACMw/-4tU5m8JkeM/s320/block_system_without_iosched.jpeg" border="0" alt=""id="BLOGGER_PHOTO_ID_5450183081142395506" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp圖二、Block I/O Layer之I/O Path&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;1. Linux Device Driver, third edition&lt;br /&gt;2. Linux Kernel Source 2.6.31&lt;br /&gt;3. &lt;a href="http://"&gt;Request-based Device-mapper multipath and Dynamic load balancing&lt;/a&gt;&lt;br /&gt;4. Understanding the Linux Kernel, Third Edition - Chapter 14. Block Device Drivers&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-3088094603806661796?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/3088094603806661796/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=3088094603806661796' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3088094603806661796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3088094603806661796'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/03/linux-block-io-layer-io-path.html' title='簡介Linux Block I/O Layer (三) - I/O Path'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_VP7dWGNif7M/S6LqemBO5yI/AAAAAAAACMY/Z4j3PCTZADo/s72-c/generic_block_dev_io_path.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-6464681277549895167</id><published>2010-03-18T13:52:00.005+08:00</published><updated>2010-03-18T16:13:46.258+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Request'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Block I/O Layer'/><category scheme='http://www.blogger.com/atom/ns#' term='BIO (Block I/O)'/><title type='text'>簡介Linux Block I/O Layer (二) - 探討BIO (Block I/O) and Request 結構</title><content type='html'>上一篇文章簡單介紹page, bio和request結構的定位，本篇文章著重於探討bio與request結構是如何串起來的。底下將分別介紹reqeust queue、request、bio與bio_vec等資料結構。首先，下圖展示這四個資料結構的關係。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_VP7dWGNif7M/S6HDGnHSc3I/AAAAAAAACMM/9h_RTJzWq2Q/s1600-h/rq_struct.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 211px;" src="http://4.bp.blogspot.com/_VP7dWGNif7M/S6HDGnHSc3I/AAAAAAAACMM/9h_RTJzWq2Q/s320/rq_struct.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5449851542441194354" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Request Queue&lt;/span&gt;&lt;br /&gt;    Request Queue用來將待處理的request串成一個&lt;a href="http://adrianhuang.blogspot.com/2007/10/linux-kernel-listhead.html"&gt;雙向的鏈結串列&lt;/a&gt;，此結構 (struct request_queue)定義在include/linux/blkdev.h檔頭檔。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Request&lt;/span&gt;&lt;br /&gt;一個request資料結構，即表示一次block I/O傳輸請求。結構裡的queuelist便是將整個request串起來的成員，bio成員代表該request所欲傳輸block I/O個數，buffer成員代表當前資料傳輸的buffer區塊。request資料結構裡還有許多其它成員，詳見include/linux/blkdev.h標頭檔。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;BIO (Block I/O)&lt;/span&gt;&lt;br /&gt;當block I/O layer上層 (&lt;a href="http://adrianhuang.blogspot.com/2010/03/linux-block-driver-layer-page-bio-block.html"&gt;可參考此篇文章的圖&lt;/a&gt;，Ex: 檔案系統或虛擬記憶體子系統)欲傳輸某一區塊時，該層便會產生一個bio結構並交由Block I/O Layer，Block I/O Layer將新請求的bio併入現有的request結構裡 (前提是該request結構裡的bio所欲傳輸的區塊磁區剛好跟新請求的bio所欲傳輸的區塊磁區相近，如此變能發揮更大的傳輸效益)，或者產生一個新的request結構並將此bio併入此request結構，此結構 (struct request_queue)定義在include/linux/bio.h標頭檔。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;bio_vec (BIO Vector)&lt;/span&gt;&lt;br /&gt;bio結構裡有一個稱為bi_io_vec一維陣列的成員，該陣列成員紀錄欲傳輸的資料緩衝區在記憶體何處。&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;1. Linux Device Driver, third edition&lt;br /&gt;2. Linux Kernel Source 2.6.31 &lt;br /&gt;3. &lt;a href="http://www.kernel.org/doc/ols/2007/ols2007v2-pages-235-244.pdf"&gt;Request-based Device-mapper multipath and Dynamic load balancing&lt;/a&gt;&lt;br /&gt;4. Understanding the Linux Kernel, Third Edition - Chapter 14. Block Device Drivers&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-6464681277549895167?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/6464681277549895167/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=6464681277549895167' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6464681277549895167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6464681277549895167'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/03/linux-block-io-layer-bio-block-io-and.html' title='簡介Linux Block I/O Layer (二) - 探討BIO (Block I/O) and Request 結構'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_VP7dWGNif7M/S6HDGnHSc3I/AAAAAAAACMM/9h_RTJzWq2Q/s72-c/rq_struct.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-2065529616764191151</id><published>2010-03-18T09:26:00.001+08:00</published><updated>2010-03-18T14:56:09.996+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Request'/><category scheme='http://www.blogger.com/atom/ns#' term='Page'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Block I/O Layer'/><category scheme='http://www.blogger.com/atom/ns#' term='BIO (Block I/O)'/><title type='text'>簡介Linux Block I/O Layer (一) - Page, BIO (Block I/O) and Request 結構意義</title><content type='html'>Linux Block I/O Layer主要處理上層檔案系統的請求，進而將該請求往丟至低層的low-level device driver (例如: Linux SCSI Subsystem)，下圖展示出這三層的關係，由圖中可知檔案系統驅動程式主要以page結構來描述所欲存取的資料在哪裡, 接著檔案系統驅動程式將page結構轉換bio (Block I/O)，並經由submit_bio函式將該請求送至Block I/O Layer，該層主要任務便將bio結構轉換成request結構 (往後會有幾篇探討該層運作細節)，並將該request結構丟至low-level device driver，以上是簡單的介紹.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_VP7dWGNif7M/S6Caa34qrvI/AAAAAAAACMA/aYMzTC8TLYU/s1600-h/page_bio_request.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 276px;" src="http://4.bp.blogspot.com/_VP7dWGNif7M/S6Caa34qrvI/AAAAAAAACMA/aYMzTC8TLYU/s320/page_bio_request.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5449525335587204850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;1. Linux Device Driver, third edition&lt;br /&gt;2. Linux Kernel Source 2.6.31 &lt;br /&gt;3. &lt;a href="http://www.kernel.org/doc/ols/2007/ols2007v2-pages-235-244.pdf"&gt;Request-based Device-mapper multipath and Dynamic load balancing&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-2065529616764191151?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/2065529616764191151/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=2065529616764191151' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2065529616764191151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2065529616764191151'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/03/linux-block-driver-layer-page-bio-block.html' title='簡介Linux Block I/O Layer (一) - Page, BIO (Block I/O) and Request 結構意義'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_VP7dWGNif7M/S6Caa34qrvI/AAAAAAAACMA/aYMzTC8TLYU/s72-c/page_bio_request.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-8940574061688338704</id><published>2010-03-15T11:30:00.003+08:00</published><updated>2010-03-15T11:39:42.554+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sizeof'/><category scheme='http://www.blogger.com/atom/ns#' term='malloc'/><category scheme='http://www.blogger.com/atom/ns#' term='C Language'/><title type='text'>C語言malloc之sizeof使用技巧</title><content type='html'>C語言程式設計師使用結構指標時，在配置一塊記憶體時通常都會使用下列宣告描述 (粗體字):&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;struct abc {&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp char *ptr;&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp int var[20];&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp struct abc *next;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;struct abc *ptr = (struct abc *) malloc(sizeof(struct abc));&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;另一種寫法可以將程式碼簡化，將sizeof(struct abc)改成sizeof(*ptr)，如下所示:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;struct abc *ptr = malloc(sizeof(*ptr));&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;提供給各位參考.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-8940574061688338704?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/8940574061688338704/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=8940574061688338704' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8940574061688338704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8940574061688338704'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/03/cmallocsizeof.html' title='C語言malloc之sizeof使用技巧'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-6539919322299074383</id><published>2010-01-25T16:39:00.004+08:00</published><updated>2010-01-26T15:15:02.197+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='container_of'/><title type='text'>Linux Kernel: container_of 巨集</title><content type='html'>Linux驅動程式裡很常看container_of巨集，其目的為何呢? 假設Linux驅動程式只知道某一結構成員的位址，該驅動程式便可使用container_of巨集，將已知某一結構成員的位址計算出該結構的起始位址，其原型如下:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;br /&gt;#define offsetof(TYPE, MEMBER) ((size_t) &amp;amp;((TYPE *)0)-&gt;MEMBER)&lt;br /&gt;&lt;br /&gt;#define container_of(ptr, type, member) ({   \&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp     const typeof( ((type *)0)-&gt;member ) *__mptr = (ptr); \&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp (type *)( (char *)__mptr - offsetof(type,member) );})&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;假設有一結構定義如下，且我們只知道phone_num成員的位址，如此便能使用該巨集計算出該結構變數的起始位址:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;/* The student structure definition */&lt;br /&gt;typedef struct student {&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp char name[16];&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp int  id;&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp char addr[64]; &lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp char phone_num[16];&lt;br /&gt;}STUDENT, *STUDENT_PTR;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;該結構記憶體配置圖如下所示:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/etahs6A5d_906eDhI1SNNw?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_VP7dWGNif7M/S11d_VdBUcI/AAAAAAAACKs/8rHcOpECVhc/s800/struct.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 1. 結構記憶體配置圖&lt;br /&gt;&lt;br /&gt;範例程式碼:&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/p9n6zNgKwDbpiFEJi3MP0g?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_VP7dWGNif7M/S111iRVoLlI/AAAAAAAACK0/5aZ26cDyTY0/s400/code.jpeg" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 2. 範例程式碼&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;以此結構為範例來看containter_of巨集的兩行程式碼:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;◎ const typeof( ((type *)0)-&gt;member ) *__mptr = (ptr); ==&gt; 得到phone_num的位址 &lt;span style="color: rgb(255, 0, 0);"&gt;(x+84) &lt;/span&gt;，請參考Figure 1跟Figure 2。&lt;br /&gt;◎ (type *)( (char *)__mptr - offsetof(type,member) ); → (type *)( (char *)__mptr - ((size_t) &amp;amp;((type *)0)-&gt;member) ); ==&gt; 其中((size_t) &amp;amp;((type *)0)-&gt;member)這段敘述代表以零為起始位址算出member這個成員的相對位址，即為phone_num成員的相對位址，也就是&lt;span style="color: rgb(255, 0, 0);"&gt;84 &lt;/span&gt; (請參考Figure 1)。所以整個敘述變成 &lt;span style="color: rgb(255, 0, 0);"&gt; (x+84) - 84 = x &lt;/span&gt;，如此便能取得該結構變數的起始位址。&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;範例程式&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/TCN7HY0T-8zZwUZrItsZPg?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_VP7dWGNif7M/S16VLBmlz_I/AAAAAAAACK8/tRvA-8jEmOQ/s800/code_sample.jpeg" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-6539919322299074383?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/6539919322299074383/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=6539919322299074383' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6539919322299074383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6539919322299074383'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/01/linux-kernel-containerof.html' title='Linux Kernel: container_of 巨集'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_VP7dWGNif7M/S11d_VdBUcI/AAAAAAAACKs/8rHcOpECVhc/s72-c/struct.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-4707430023939425713</id><published>2010-01-22T11:32:00.002+08:00</published><updated>2010-01-22T16:31:28.778+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='kmem_cache'/><category scheme='http://www.blogger.com/atom/ns#' term='linux lookaside cache'/><category scheme='http://www.blogger.com/atom/ns#' term='slab allocator'/><title type='text'>Linux Kernel: Lookaside Cache (前瞻快取)</title><content type='html'>驅動程式往往根據使用者請求一次又一次地配置相同記憶體大小的物件。為此，Linux核心提供此需求的機制 - Lookaside cache。而此機制稱為Slab Allocator。&lt;br /&gt;&lt;br /&gt;以SCSI驅動程式為例，當使用者要讀寫硬碟資料時，會由區塊裝置驅動程式 (Block Device Driver)向SCSI層發出請求，SCSI層將此請求轉換成SCSI command的結構 (struct scsi_cmnd)，為了能快速配置與存取SCSI command，SCSI層驅動程式為每一個SCSI command結構配置lookaside cache。其用法如下:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;1. 首先，必須先配置一個快取物件導向，其函式: struct kmem_cache *&lt;br /&gt;kmem_cache_create (const char *name, size_t size, size_t align,&lt;br /&gt; unsigned long flags, void (*ctor)(void *))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp◎ name: 此快取物件名稱，此名稱會出現在/proc/slabinfo。&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp◎ size: 物件大小。&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp◎ align: 對齊字元數大小，通常為零。&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp◎ flag: 配置物件的方式，詳見include/linux/slab.h。&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp◎ ctor: 建構子函式位址。當核心成功地配置物件後，便會呼叫此函式。&lt;br /&gt;&lt;br /&gt;2. 接著，呼叫kmem_cache_alloc，配置每一個物件，其原型: void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);&lt;br /&gt;&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp◎ cachep: kmem_cache_create回傳的位址。&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp◎ flags： 詳見kmalloc的flags參數。&lt;br /&gt;&lt;br /&gt;3. 釋放記憶體: &lt;br /&gt; void kmem_cache_free(struct kmem_cache *cachep, void *objp)&lt;br /&gt; → 釋放物件，但並未釋放快取。&lt;br /&gt; void kmem_cache_destroy(struct kmem_cache *cachep) → 釋放快取。&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;範例 (取自Linux SCSI驅動程式):&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/yiLvmxU8LG3afc8oYb9XWw?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_VP7dWGNif7M/S1lXGw3GbBI/AAAAAAAACJ0/EHvM4CUHiDo/s800/scsi_kmem_cache_demo.jpeg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;1. Linux Device Driver, third edition&lt;br /&gt;2. Linux Kernel Source 2.6.31&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-4707430023939425713?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/4707430023939425713/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=4707430023939425713' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4707430023939425713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4707430023939425713'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/01/linux-kernel-lookaside-cache.html' title='Linux Kernel: Lookaside Cache (前瞻快取)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_VP7dWGNif7M/S1lXGw3GbBI/AAAAAAAACJ0/EHvM4CUHiDo/s72-c/scsi_kmem_cache_demo.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-7881403611768097631</id><published>2010-01-15T16:57:00.003+08:00</published><updated>2010-01-15T19:37:52.653+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='__initdata'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='__init'/><category scheme='http://www.blogger.com/atom/ns#' term='free_initmem'/><title type='text'>Linux Kernel: __init, __initdata屬性</title><content type='html'>在trace Linux核心原始碼很常看到__init和__initdata兩個屬性。其原型如下:&lt;br /&gt;&lt;blockquote&gt;#define __init  __section(.init.text) __cold notrace&lt;br /&gt;#define __initdata __section(.init.data)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;只要函數被定義__init屬性，代表此函數的所有內容被編譯器放置在.init.text節區。此節區代表該函數只會執行一次，此後就不會再執行，因此執行完該函數，核心會將該函數所佔記憶體空間釋放出來。__init屬性非常適合裝置驅動程式的init_module函數，其範例宣告如下:&lt;br /&gt;&lt;blockquote&gt;static int __init dm_init(void); (from linux-source-2.6.31/drivers/md/dm.c)&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;利用objdump觀察dm_init函數被放置在哪個節區:&lt;br /&gt;&lt;blockquote&gt;adrian@adrian-laptop:/usr/src/linux-source-2.6.31$ objdump -x drivers/md/built-in.o | grep md_init&lt;br /&gt;&lt;font color="#0000FF"&gt;00000000 l     F  .init.text 000000de md_init &lt;/font&gt;&lt;br /&gt;00000000 l     O .initcall4.init    00000004 __initcall_md_init4&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;__initdata屬性跟__init屬性的作用大同小異，唯一不同在於前者放置在.init.data節區。&lt;br /&gt;&lt;br /&gt;範例:&lt;br /&gt;&lt;blockquote&gt;static int (*_inits[])(void) __initdata = {&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp    local_init,&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp dm_target_init,&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp dm_linear_init,&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp dm_stripe_init,&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp dm_kcopyd_init,&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp dm_interface_init,&lt;br /&gt;};&lt;/blockquote&gt;&lt;br /&gt;利用objdump觀察_inits變數被放置在哪個節區:&lt;br /&gt;&lt;blockquote&gt; adrian@adrian-laptop:/usr/src/linux-source-2.6.31$ objdump -x drivers/md/built-in.o | grep _inits&lt;br /&gt;&lt;font color="#0000FF"&gt;00000000 l     O .init.data 00000018 _inits &lt;/font&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;問題來了，釋放記憶體的工作由核心的哪一函數負責呢? 答案是: free_initmem (arch/x86/mm/init.c)&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;&lt;a href="http://kernelnewbies.org/FAQ/InitExitMacros"&gt;FAQ/InitExitMacros&lt;/a&gt;&lt;br /&gt;Linux Kernel Source 2.6.31&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-7881403611768097631?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/7881403611768097631/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=7881403611768097631' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7881403611768097631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7881403611768097631'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/01/linux-kernel-init-initdata.html' title='Linux Kernel: __init, __initdata屬性'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-8389823103879128687</id><published>2010-01-15T11:11:00.002+08:00</published><updated>2010-01-15T11:48:41.063+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='protected_mode_jump'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Booting'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembly'/><title type='text'>An Introduction to Linux Kernel Booting Sequence Part 3</title><content type='html'>&lt;a href="http://adrianhuang.blogspot.com/2010/01/introduction-to-linux-kernel-booting.html"&gt;上篇文章&lt;/a&gt;提到go_to_protected_mode函式最後會執行由組合語言所撰寫的函式protected_mode_jump，此函式工作如下:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    函式呼叫原型:&lt;br /&gt;       protected_mode_jump(boot_params.hdr.code32_start, (u32)&amp;boot_params + (ds() &lt;&lt; 4));&lt;br /&gt;&lt;br /&gt;    其程式碼:&lt;br /&gt;       &lt;br /&gt;      /*&lt;br /&gt; * void protected_mode_jump(u32 entrypoint, u32 bootparams);&lt;br /&gt; */&lt;br /&gt;GLOBAL(protected_mode_jump)&lt;br /&gt; movl %edx, %esi  # Pointer to boot_params table&lt;br /&gt;&lt;br /&gt; xorl %ebx, %ebx   &lt;br /&gt; movw %cs, %bx&lt;br /&gt; shll $4, %ebx&lt;br /&gt; addl %ebx, 2f&lt;br /&gt; jmp 1f   # Short jump to serialize on 386/486&lt;br /&gt;1:&lt;br /&gt;&lt;br /&gt; movw $__BOOT_DS, %cx&lt;br /&gt; movw $__BOOT_TSS, %di &lt;br /&gt;&lt;br /&gt;       &lt;span style="font-weight:bold;"&gt; &lt;span style="font-style:italic;"&gt;### 設定x86之cr0暫存器的PE位元，如此便能進入proctected-mode&lt;/span&gt;&lt;span style="font-style:italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; movl %cr0, %edx&lt;br /&gt; orb $X86_CR0_PE, %dl # Protected mode&lt;br /&gt; movl %edx, %cr0&lt;br /&gt;&lt;br /&gt; # Transition to 32-bit mode&lt;br /&gt; .byte 0x66, 0xea  # ljmpl opcode&lt;br /&gt;2: .long in_pm32   # offset&lt;br /&gt; .word __BOOT_CS  # segment&lt;br /&gt;ENDPROC(protected_mode_jump)&lt;br /&gt;&lt;br /&gt; .code32&lt;br /&gt; .section ".text32","ax"&lt;br /&gt;GLOBAL(in_pm32)&lt;br /&gt; # Set up data segments for flat 32-bit mode&lt;br /&gt; movl %ecx, %ds&lt;br /&gt; movl %ecx, %es&lt;br /&gt; movl %ecx, %fs&lt;br /&gt; movl %ecx, %gs&lt;br /&gt; movl %ecx, %ss&lt;br /&gt; # The 32-bit code sets up its own stack, but this way we do have&lt;br /&gt; # a valid stack if some debugging hack wants to use it.&lt;br /&gt; addl %ebx, %esp&lt;br /&gt;&lt;br /&gt; # Set up TR to make Intel VT happy&lt;br /&gt; ltr %di&lt;br /&gt;&lt;br /&gt; # Clear registers to allow for future extensions to the&lt;br /&gt; # 32-bit boot protocol&lt;br /&gt; xorl %ecx, %ecx&lt;br /&gt; xorl %edx, %edx&lt;br /&gt; xorl %ebx, %ebx&lt;br /&gt; xorl %ebp, %ebp&lt;br /&gt; xorl %edi, %edi&lt;br /&gt;&lt;br /&gt; # Set up LDTR to make Intel VT happy&lt;br /&gt; lldt %cx&lt;br /&gt;&lt;br /&gt;        &lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;## 跳至code32_start的標籤&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; jmpl *%eax   # Jump to the 32-bit entrypoint&lt;br /&gt;ENDPROC(in_pm32)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;至於code32_start在哪裡呢? 此標籤定義在arch/x86/boot/header.S，如下所示:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;code32_start:    # here loaders can put a different&lt;br /&gt;     # start address for 32-bit code.&lt;br /&gt;  .long 0x100000 # 0x100000 = default for big kernel&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;也就是說，核心已做完real-mode Linux程式碼該做的事情，並跳至protected-mode Linux程式碼的起始位址 (1MB)，請看下圖:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/4221596496/" title="Flickr 上 adrianhuang0701 的 linux kernel ram content after loading the image into the ram"&gt;&lt;img src="http://farm5.static.flickr.com/4021/4221596496_052643f41d.jpg" width="500" height="369" alt="linux kernel ram content after loading the image into the ram" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;[Reference]&lt;br /&gt;&lt;a href="http://duartes.org/gustavo/blog/post/kernel-boot-process"&gt;【The Kernel Boot Process】&lt;/a&gt;&lt;br /&gt;【Linux Kernel Source 2.6.31】&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-8389823103879128687?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/8389823103879128687/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=8389823103879128687' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8389823103879128687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8389823103879128687'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/01/introduction-to-linux-kernel-booting_15.html' title='An Introduction to Linux Kernel Booting Sequence Part 3'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4021/4221596496_052643f41d_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-3660084125774168389</id><published>2010-01-12T14:11:00.006+08:00</published><updated>2010-01-13T10:46:14.815+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Booting'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembly'/><title type='text'>An Introduction to Linux Kernel Booting Sequence Part 2</title><content type='html'>&lt;a href="http://adrianhuang.blogspot.com/2009/12/introduction-to-linux-kernel-booting.html"&gt;上篇文章&lt;/a&gt;Linux核心被載入記憶體並執行start_of_setup標籤(arch/x86/boot/header.S)，在start_of_setup標籤末段會執行由C語言撰寫的main函式 (arch/x86/boot/main.c)，此函式工作如下所示:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;1. 複製開機標頭 (boot header) 至 &lt;a href="http://en.wikipedia.org/wiki/Zero_page"&gt;zero page&lt;/a&gt;&lt;br /&gt;2. 設定heap_end變數&lt;br /&gt;3. 偵測記憶體layout&lt;br /&gt;4. 設定&lt;a href="http://www.pbdr.com/ostips/keyrrate.htm"&gt;鍵盤重複率 (Keyboard Repeat Rate)&lt;/a&gt;&lt;br /&gt;5. 查詢&lt;a href="http://www.mjmwired.net/kernel/Documentation/mca.txt"&gt;MCA (Micro Channel Architecture)&lt;/a&gt; 資訊&lt;br /&gt;6. 查詢&lt;a href="http://en.wikipedia.org/wiki/SpeedStep"&gt;Intel SpeedStep&lt;/a&gt;&lt;br /&gt;7. 設定video模式&lt;br /&gt;8. 進入protected-mode (go_to_protected_mode，arch/x86/boot/pm.c)&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;其中3-6項，經由BIOS呼叫 (intcall，arch/x86/boot/bioscall.S)，以便向BIOS取到相關的資訊。&lt;br /&gt;main函式最後呼叫go_to_protected_mode函式，以便從real-mode轉換至protected-mode。&lt;br /&gt;&lt;br /&gt;在真正進入protected-mode之前，有幾項工作必須先被執行，也就是go_to_protected_mode函式裡所做的事情，如下所示:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt; 1. 設定&lt;a href="http://en.wikipedia.org/wiki/A20_line"&gt;A20位址線&lt;/a&gt;，如此便能存取超過1MB以後的資料 (因為在real-mode，只能存取1MB以下的資料)。&lt;br /&gt;&lt;br /&gt;2. 設定idt (interrupt descriptor table)。在real-mode，interrupt vector table的起始位址是從記憶體零的位址開始算起。然而，在protected-mode，interrupt vector table是儲存於CPU的暫存器 (IDTR，Interrupt Descriptor Table Register)，因此轉換至protected-mode之前，必須先設定idt。&lt;br /&gt;&lt;br /&gt;3. 設定gdt (global descriptor table)。由於，real-mode與proctected-mode位址轉換 (由邏輯位址 [logical address] 轉換成線性位址 [linear address])，詳見&lt;a href="http://en.wikipedia.org/wiki/X86_memory_segmentation"&gt;x86_memory_segmentation&lt;/a&gt;。因此轉換至protected-mode之前，必須先設定gdt，以便能正確地根據logical address轉換成linear address。&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;在go_to_protected_mode函式最後會執行由組合語言所撰寫的函式protected_mode_jump，此函式便是設定CPU為protected-mode，細節留到下回做進一步解釋。&lt;br /&gt;&lt;br /&gt;【Reference】 &lt;a href="http://duartes.org/gustavo/blog/post/kernel-boot-process"&gt;The Kernel Boot Process&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-3660084125774168389?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/3660084125774168389/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=3660084125774168389' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3660084125774168389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3660084125774168389'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2010/01/introduction-to-linux-kernel-booting.html' title='An Introduction to Linux Kernel Booting Sequence Part 2'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-2160649529148002428</id><published>2009-12-25T17:31:00.004+08:00</published><updated>2009-12-28T15:53:22.095+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Booting'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembly'/><title type='text'>An Introduction to Linux Kernel Booting Sequence Part 1</title><content type='html'>此系列文章將著重於探討Linux x86核心開機過程,&lt;br /&gt;其中, 假設BIOS跟Boot Loader (GRUB, for example) 運行正常, 且Boot Loader已將核心 (/boot/vmlinuz-2.6.31-16-generic) 載入記憶體並跳至載入記憶體之起始位置執行.&lt;br /&gt;&lt;br /&gt;Linux核心主要可以分為兩大部份: 1. 執行於CPU之&lt;a href="http://en.wikipedia.org/wiki/Real_mode"&gt;real mode&lt;/a&gt;的核心程式碼 2. 執行於CPU之&lt;a href="http://en.wikipedia.org/wiki/Protected_mode"&gt;protected mode&lt;/a&gt;的核心程式碼. 然而這兩大部份被載入至不同的記憶體區段: 1. real mode核心程式碼載入至0-640KB的某一區間, 2. protected mode核心程式碼載入至1MB記憶體位址. 如下所示:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/4221596496/" title="Flickr 上 adrianhuang0701 的 linux kernel ram content after loading the image into the ram"&gt;&lt;img src="http://farm5.static.flickr.com/4021/4221596496_052643f41d.jpg" width="500" height="369" alt="linux kernel ram content after loading the image into the ram" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Figure 1. Linux kernel RAM content after loading the Linux kernel image into RAM&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;首先第一個被執行的Linux核心檔案為arch/x86/boot/header.S，此檔案由組合語言所撰寫，此檔案前512位元組 (其中有15個位元組為核心標頭) 為早期的核心開機磁區，但現今的boot loader直接跳過此512位元組。緊接著在512位元組之後，即為Linux核心執行的起始點，底下展示此起始點的兩行程式碼 (以Linux核心原始碼版本2.6.31為例)：&lt;br /&gt;&lt;blockquote&gt;.byte 0xeb  # short (2-byte) jump&lt;br /&gt;.byte start_of_setup-1f&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;此兩行代表跳至start_of_setup標籤。".byte  0xeb"  (arch/x86/boot/header.S:112)代表&lt;a href="http://mirror.href.com/thestarman/asm/2bytejumps.htm"&gt;two-bytes jmp&lt;/a&gt;組合語言指令。".byte start_of_setup-1f"  (arch/x86/boot/header.S:113)的"f"代表&lt;a href="http://mirror.href.com/thestarman/asm/2bytejumps.htm"&gt;forward short jump&lt;/a&gt;，"start_of_setup-1"代表用"start_of_setup" (arch/x86/boot/header.S:241)標籤起始位址減去"1" (arch/x86/boot/header.S:114)標籤起始位址。&lt;br /&gt;&lt;br /&gt;所以上述兩個位元組即代表： 以目前的位址向下跳至n個位元組 (即start_of_setup-1)，因此便能正確地跳至start_of_setup標籤。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;範例 (以Ubuntu 9.10之2.6.31-16-generic核心為例)&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;此範例利用hexdump將Linux核心dump出來，並觀看其16進制碼用以對照上述之論述。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt; adrian@adrian-desktop:/boot$ hexdump vmlinuz-2.6.31-16-generic &gt; ~/vmlinuz-2.6.31-16-generic-hexdump&lt;br /&gt;adrian@adrian-desktop:/boot$ gvim ~/vmlinuz-2.6.31-16-generic-hexdump&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;其結果如下所示:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/4221702206/" title="Flickr 上 adrianhuang0701 的 hexdump"&gt;&lt;img src="http://farm5.static.flickr.com/4021/4221702206_12722ec498.jpg" width="500" height="445" alt="hexdump" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Figure 2. Hexdump from Linux Kernel&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;其中，0xAA55為Linux早期的核心開機磁區最後一個位元組(第512個位元組，arch/x86/boot/header.S:103)。0x62eb代表往下跳至62個位元組，即0x00000262位址。&lt;br /&gt;&lt;br /&gt;本篇文章只介紹Linux之real-mode核心程式碼的entry point，往後會有陸陸續續的文章繼續探討。&lt;br /&gt;&lt;br /&gt;【Reference】&lt;br /&gt;&lt;a href="http://duartes.org/gustavo/blog/post/kernel-boot-process"&gt;The Kernel Boot Process&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-2160649529148002428?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/2160649529148002428/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=2160649529148002428' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2160649529148002428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2160649529148002428'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2009/12/introduction-to-linux-kernel-booting.html' title='An Introduction to Linux Kernel Booting Sequence Part 1'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4021/4221596496_052643f41d_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-4946490583340437709</id><published>2009-12-18T14:12:00.001+08:00</published><updated>2009-12-18T14:16:24.273+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='亂碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Flash'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Firefox'/><title type='text'>[Ubunut] 解決Firefox Flash網頁亂碼</title><content type='html'>Follow up:&lt;br /&gt;    1. sudo rm -f /etc/fonts/conf.d/49-sansserif.conf&lt;br /&gt;    2. restart firefox&lt;br /&gt;&lt;br /&gt;大功告成.&lt;br /&gt;&lt;br /&gt;[Reference] http://blog.xuite.net/maxkerr/blog/17037089&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-4946490583340437709?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/4946490583340437709/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=4946490583340437709' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4946490583340437709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4946490583340437709'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2009/12/ubunut-firefox-flash.html' title='[Ubunut] 解決Firefox Flash網頁亂碼'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-5754442928876947347</id><published>2009-05-21T18:20:00.004+08:00</published><updated>2009-05-26T18:34:50.354+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='unlikely'/><category scheme='http://www.blogger.com/atom/ns#' term='likely'/><title type='text'>likely() and unlikely() macro in Linux kernel</title><content type='html'>Linux核心原始碼，經常出現兩個巨集：likely() and unlikely()，如下所示:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;#define likely(x) __builtin_expect(!!(x), 1)&lt;br /&gt;#define unlikely(x) __builtin_expect(!!(x), 0)&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;重點就是__builtin_expect這個函式的意義。此函式用來告訴編譯器，哪些程式區段可做預測。&lt;br /&gt;底下為__builtin_expect的原型:&lt;br /&gt;&lt;blockquote&gt;long __builtin_expect(long EXP, long C)&lt;br /&gt;此函式__builtin_expect有兩大重點:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;__builtin_expect的回傳值即EXP這個判斷式。&lt;/li&gt;&lt;li&gt;__builtin_expect語意上，是期待(EXP == C)。&lt;/li&gt;&lt;/ol&gt;例子一:&lt;br /&gt;if (__builtin_expect(x, 1))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;do_something();&lt;br /&gt;&lt;br /&gt;此敘述告知編譯器，x變數期待是1 (上述重點2), 且由於x=1, 所以__builtin_expect回傳值便是1(上述重點1)，因此編譯器可以大膽預測do_something()一定會被執行到。因此便能將處理器的管線(Pipe  Line)功能發揮的淋漓盡致。&lt;br /&gt;&lt;br /&gt;例子二:&lt;br /&gt;if (__builtin_expect(x, 0))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;do_something1();&lt;br /&gt;else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;do_something2();&lt;br /&gt;&lt;br /&gt;此敘述告知編譯器，x變數期待是0 (上述重點2), 且由於x=0, 所以__builtin_expect回傳值便是0(上述重點1)，因此編譯器可以大膽預測do_something2()一定會被執行到，而不是預測執行do_something1()。&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;總結likely()與unlikely()巨集:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;if(likely(x)) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;預測想要執行的原始碼&lt;br /&gt;} else {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if(unlikely(x)) {&lt;br /&gt;} else {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;預測想要執行的原始碼&lt;br /&gt;}&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;[Reference]&lt;br /&gt;1. &lt;a href="http://kernelnewbies.org/FAQ/LikelyUnlikely"&gt;FAQ/LikelyUnlikely&lt;/a&gt;&lt;br /&gt;2. &lt;a href="http://blog.richliu.com/2007/02/01/428/"&gt;richliu's blog&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-5754442928876947347?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/5754442928876947347/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=5754442928876947347' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5754442928876947347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5754442928876947347'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2009/05/likely-and-unlikely-macro-in-linux.html' title='likely() and unlikely() macro in Linux kernel'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-4392815287607457260</id><published>2009-05-19T19:28:00.004+08:00</published><updated>2009-05-19T19:52:21.061+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Preprocessor'/><category scheme='http://www.blogger.com/atom/ns#' term='C Language'/><category scheme='http://www.blogger.com/atom/ns#' term='stringify operator'/><category scheme='http://www.blogger.com/atom/ns#' term='define macro'/><title type='text'>The Stringify Operator (#) in C</title><content type='html'>繼上次提到Token-pasting operator (##) in C文章後, 這次講一下在C語言define巨集參數使用的另一種方法, 在參數名稱前加一個#運算子, 此運算子代表所帶入的參數會被編譯器視為"字串", 所以#運算子又被稱為字串化運算子,  底下為一簡單的例子:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;#define GET_RESULT(exp) printf(#exp "=%d\n", exp)&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GET_RESULT(3+2);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return ;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/stdio.h&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-4392815287607457260?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/4392815287607457260/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=4392815287607457260' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4392815287607457260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4392815287607457260'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2009/05/stringify-operator-in-c.html' title='The Stringify Operator (#) in C'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-8325059587443610699</id><published>2009-05-18T18:18:00.005+08:00</published><updated>2010-01-19T09:12:27.905+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Preprocessor'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='C Language'/><category scheme='http://www.blogger.com/atom/ns#' term='##'/><category scheme='http://www.blogger.com/atom/ns#' term='Token-pasting'/><title type='text'>Token-pasting operator(##) in C</title><content type='html'>我們都知道C語言define前端處理假指令用來定義變數、字串或幾行的原始碼(統稱為巨集, Macro)。&lt;br /&gt;當某一巨集被定義為參數帶入之巨集, 我們最常用的就是把該參數當作變數或指標來使用，如下所示:&lt;br /&gt;&lt;blockquote&gt;#define INC_IDX(val, size)  (++val % size)  -&gt; 以參數為變數之值帶入此巨集&lt;br /&gt;#define GET_DATA(ptr)       (ptr-&gt;data)  -&gt; 以參數為指標帶入此巨集&lt;/blockquote&gt;&lt;br /&gt;然而，我們可以把巨集所帶入的參數當作為識別子(Token)的一部分，如下所示:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;stdio.h&gt;&lt;br /&gt;&lt;br /&gt;int class_num = 9;&lt;br /&gt;int class_stds = 10;&lt;br /&gt;&lt;br /&gt;#define GET_MEMBER(postfix)   class_ ## postfix&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    printf("class_num: %d\n", GET_MEMBER(num));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    printf("class_stds: %d\n", GET_MEMBER(stds));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;    return 0;&lt;br /&gt;}&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;如上列所示，class_num可以經由GET_MEMBER巨集(帶入部份識別子, 也就是num)取得，此參數傳遞方法稱為Token-pasting operator，這是一個非常好用的方法, 提供給大家參考。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-8325059587443610699?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/8325059587443610699/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=8325059587443610699' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8325059587443610699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8325059587443610699'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2009/05/gnu-c.html' title='Token-pasting operator(##) in C'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-5181263526423668720</id><published>2008-12-19T13:52:00.003+08:00</published><updated>2008-12-19T14:00:41.541+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linus'/><title type='text'>Linus大神的十句經典名言~</title><content type='html'>Linus的十句經典名言果然是太妙了, 噹了M$這句"Microsoft isn't evil, they just make really crappy operating systems.", 真是一針見血. 還有這句“My name is Linus, and I am your God.”, 你真的是一位大神!!&lt;br /&gt;&lt;br /&gt;【詳情】&lt;br /&gt;&lt;a href="http://www.businessreviewonline.com/os/archives/2008/06/the_10_best_lin.html"&gt;Linus大神十句經典名言&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-5181263526423668720?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/5181263526423668720/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=5181263526423668720' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5181263526423668720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/5181263526423668720'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2008/12/linus.html' title='Linus大神的十句經典名言~'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-4911514497386179011</id><published>2008-10-16T13:38:00.003+08:00</published><updated>2008-10-16T13:45:18.363+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Business Travel'/><title type='text'>Hong Kong</title><content type='html'>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&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-4911514497386179011?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/4911514497386179011/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=4911514497386179011' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4911514497386179011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4911514497386179011'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2008/10/hong-kong.html' title='Hong Kong'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-4357640221676768763</id><published>2008-08-03T00:13:00.003+08:00</published><updated>2008-08-03T00:21:11.525+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux、網路芳鄰、sshfs'/><title type='text'>類似網路芳鄰的好物 (sshfs)</title><content type='html'>提到Linux網路芳鄰，大家第一個想到必是samba，但有一套小程式也有此功能：sshfs。只要兩台主機都有安裝ssh server，便可互相掛載資料夾，指令如下：&lt;br /&gt;&lt;br /&gt;$ sshfs user@remote_host_ip:dir local_host_mountpoint&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-4357640221676768763?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/4357640221676768763/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=4357640221676768763' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4357640221676768763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4357640221676768763'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2008/08/sshfs.html' title='類似網路芳鄰的好物 (sshfs)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-2710199828255966139</id><published>2007-11-11T16:49:00.000+08:00</published><updated>2007-11-11T16:52:44.262+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel、skype、webcam'/><title type='text'>Skype 2.0 Beta for Linux支援Webcam!</title><content type='html'>Skype 2.0 Beta for Linux支援webcam功能囉!! 看起來似乎還不賴~~有興趣的可以看看此&lt;a href="http://share.skype.com/sites/linux/2007/11/skype_20_beta_for_linux_with_video.html"&gt;Link&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-2710199828255966139?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/2710199828255966139/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=2710199828255966139' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2710199828255966139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2710199828255966139'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/11/skype-20-beta-for-linuxwebcam.html' title='Skype 2.0 Beta for Linux支援Webcam!'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-7953977088582022815</id><published>2007-11-07T18:48:00.000+08:00</published><updated>2007-11-09T12:47:33.767+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ICOS、COSCUP'/><title type='text'>Nov 4, 2007 ICOS/COSCUP Day 3</title><content type='html'>&lt;span style="font-weight: bold;"&gt;[開放組織新人秀]&lt;/span&gt;&lt;br /&gt;這場會議主要由社群或ㄧ些組織介紹如何法人化的議題。其中，最帥應該算是&lt;a href="http://knightfeng.org/blog/"&gt;乃特大&lt;/a&gt;吧!!! ㄧ整個砲轟ICOS主辦單位與SLAT理事長，只能說乃特大真的是太猛了!!!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;[BSD]&lt;/span&gt;&lt;br /&gt;由幾位玩BSD前被介紹FreeBSD相關議題，其中也提到ㄧ套新穎檔案系統─ZFS，感覺ZFS似乎還蠻強大的，有興趣的倒是也可以研究研究。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;[Embedded system part1]&lt;/span&gt;&lt;br /&gt;首先，由&lt;span style="color: rgb(255, 0, 0);"&gt;戒色v&lt;/span&gt; (&lt;a href="http://blog.linux.org.tw/%7Ejserv/"&gt;jserv&lt;/a&gt;大)主講『&lt;span class="postbody"&gt;快快樂樂設計嵌入式即時作業系統』，又再一次看到jserv新的鉅作─設計一套RT OS，只能說jserv果然強啊!!!&lt;br /&gt;&lt;br /&gt;接著，由Joseph介紹DirectFB的議題，還蠻有趣的。&lt;br /&gt;&lt;br /&gt;最後由&lt;a href="http://www.jollen.org/"&gt;Jollen&lt;/a&gt;大介紹OpenMoko議題，這場應該算是我最想聽的ㄧ場之ㄧ，Jollen是個強者啊!!! 強力介紹Jollen大的blog。&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;[Embedded system part2]&lt;/span&gt;&lt;br /&gt;&lt;span class="postbody"&gt;這場介紹openWRT的議題，其中比較有趣的是介紹如何Hackㄧ台router，讚!!!&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-7953977088582022815?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/7953977088582022815/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=7953977088582022815' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7953977088582022815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7953977088582022815'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/11/nov-2-2007-icoscoscup-day-3.html' title='Nov 4, 2007 ICOS/COSCUP Day 3'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-3866102254737681703</id><published>2007-11-02T23:47:00.000+08:00</published><updated>2007-11-03T00:12:26.358+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux 、COSCUP、ICOS、Open Source  Conference'/><title type='text'>Nov 2, 2007 ICOS/COSCUP Day 1</title><content type='html'>今天特地請假，衝去國科會參加ICOS/COSCUP 2007，抵達會場大約10:00，報到完後，便走進會議室準備聽第一個session的演講。在會議室哩，遇到來自kalug的shawn與 kevin，他們居然坐半夜兩點的夜車趕上來，天啊!!!你們真是熱血啊!!!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;『Session 1 自由軟體與商業軟體的對話』&lt;/span&gt;&lt;br /&gt;此演講可說是自由軟體大戰M$啊!! 看著洪朝貴老師ㄧ直噹M$台灣協理，感覺M$台灣協理也快招架不住，也感覺這位協理也有點無辜，或許M$政策並非由她所主導。Anyway，此場會議便充滿著火藥味結束。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;『Session 2 OpenSolaris Distro: The Road to Solaris Next』&lt;/span&gt;&lt;br /&gt;講者ㄧ直推銷他們所開發的Solaris作業系統，說這是世界上最優秀的OS喲。緊接著，介紹Sun最近的ㄧ個專案─OpenSolaris，此為一套開放的Solaris作業系統，有興趣可以在Google打OpenSolaris關鍵字便能找到。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;『Session 3 Linux LAN驅動程式開發』&lt;/span&gt;&lt;br /&gt;此會議有Thinker主講有關網卡驅動程式開發，由於自己已有此方面相關經驗，所以覺得主講著講的還蠻清楚。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;『Session 4 Embedded system Security』&lt;/span&gt;&lt;br /&gt;此會議由徐千洋前輩主講，這應該是今天最精采的ㄧ場吧! Buffer Overflow講的簡單明瞭，一整個讚啊!!真不愧是Linux C函式庫的作者啊!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-3866102254737681703?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/3866102254737681703/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=3866102254737681703' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3866102254737681703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3866102254737681703'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/11/nov-2-2007-icoscoscup-day-1.html' title='Nov 2, 2007 ICOS/COSCUP Day 1'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-3749118333636873726</id><published>2007-10-29T19:33:00.000+08:00</published><updated>2007-10-30T20:09:49.807+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Vim、Plugin、Word Completion'/><title type='text'>Vim Tip: 識別子補齊 (Word Completion)</title><content type='html'>用IDE寫過程式的人，應該都體會過識別子補齊的功能。譬如說，忘記某一結構的某一成員的全名，通常只要記得幾個字母，IDE便會秀出一個符合這幾個字母的小方塊，以供您選擇。&lt;br /&gt;&lt;br /&gt;Vim當然有此功能，在Insert mode，把游標移到識別子上，再按&lt;span style="color: rgb(255, 0, 0);"&gt;Ctrl+n&lt;/span&gt; 或 &lt;span style="color: rgb(255, 0, 0);"&gt;Ctrl+p&lt;/span&gt;就可以了。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;範例&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;下圖在某一結構詢問有哪些成員。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/1799148078/" title="相片分享"&gt;&lt;img src="http://farm3.static.flickr.com/2275/1799148078_8dab3a336c_o.png" alt="1" height="973" width="1220" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;按Ctrl+n變出現下圖之結果:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/1799148120/" title="相片分享"&gt;&lt;img src="http://farm3.static.flickr.com/2021/1799148120_bce421e13e_o.png" alt="2" height="973" width="1220" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;當然忘記某一函式也行。例如，打mem然後再按Ctrl+n，如下兩圖所示:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/1799148134/" title="相片分享"&gt;&lt;img src="http://farm3.static.flickr.com/2013/1799148134_532ae2501f_o.png" alt="3" height="973" width="1220" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/1799148144/" title="相片分享"&gt;&lt;img src="http://farm3.static.flickr.com/2142/1799148144_5640fa9b48_o.png" alt="4" height="973" width="1220" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[Reference]&lt;br /&gt;&lt;a href="http://www.blogger.com/img/gl.link.gif"&gt;Vim官網&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-3749118333636873726?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/3749118333636873726/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=3749118333636873726' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3749118333636873726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3749118333636873726'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/vim-tip.html' title='Vim Tip: 識別子補齊 (Word Completion)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-2069242260951582205</id><published>2007-10-24T22:26:00.000+08:00</published><updated>2007-10-24T22:30:26.576+08:00</updated><title type='text'>Adrian's Blog被LinuxByExample收錄?</title><content type='html'>剛剛去&lt;a href="http://linux.byexamples.com/"&gt;LinuxByExample&lt;/a&gt;逛了一下，發現小弟的Blog被該網站收錄至"Chinese Linux Blog"，大驚!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-2069242260951582205?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/2069242260951582205/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=2069242260951582205' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2069242260951582205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2069242260951582205'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/adrians-bloglinuxbyexample.html' title='Adrian&apos;s Blog被LinuxByExample收錄?'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-2199864075991992274</id><published>2007-10-24T18:35:00.001+08:00</published><updated>2007-10-24T18:54:57.407+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu、Gvim、亂碼、Ubuntu 7.10 (Gusty'/><title type='text'>升級Ubuntu 7.10 (Gusty)後，Gvim亂碼!</title><content type='html'>最近把Ubuntu升級至7.10 (Gusty)，發現執行Gvim居然會亂碼，囧rz..且還有Assertion。&lt;blockquote&gt;** (gvim:9348): CRITICAL **: ascii_glyph_table_init: assertion `gui.ascii_glyphs-&gt;num_glyphs == sizeof(ascii_chars)' failed&lt;br /&gt;&lt;/blockquote&gt;結果是Gvim默認的一些字型(Ex: Sans, Monspace) 搞的鬼。因此換別的字型就可以用了，編輯~/.vimrc加入下列幾行：&lt;br /&gt;&lt;blockquote&gt;if has("gui")&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set guifont=Bitstream\ Vera\ Sans\ Mono\ 12&lt;br /&gt;endif&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-2199864075991992274?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/2199864075991992274/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=2199864075991992274' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2199864075991992274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2199864075991992274'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/ubuntu-710-gustygvim.html' title='升級Ubuntu 7.10 (Gusty)後，Gvim亂碼!'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-731406031562108162</id><published>2007-10-22T19:51:00.000+08:00</published><updated>2007-10-22T19:58:49.613+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Upgrade'/><title type='text'>輕輕鬆鬆升級Ubuntu (7.04 -&gt; 7.10)</title><content type='html'>今天在網路上看到四元兄有關&lt;a href="http://picasaweb.google.com/fourdollars/UpgradeUbuntu704To710"&gt;升級Ubuntu的圖文說明&lt;/a&gt;，簡單明瞭，推啊。重點是完全不用修改/etc/apt/sources.list，推薦給大家!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-731406031562108162?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/731406031562108162/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=731406031562108162' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/731406031562108162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/731406031562108162'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/ubuntu-704-710.html' title='輕輕鬆鬆升級Ubuntu (7.04 -&gt; 7.10)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-1395122013678256405</id><published>2007-10-19T22:26:00.000+08:00</published><updated>2007-10-19T22:45:01.993+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ICOS、COSCUP'/><title type='text'>ICOS/COSCUP 2007</title><content type='html'>一年一度的台灣開放源碼研討會將於2007 11月1日至11月4日 (&lt;a href="http://www.slat.org/icos2007/index.php"&gt;ICOS 2007&lt;/a&gt;)在國科會科技大樓舉行，其中較有興趣的是嵌入式系統與驅動程式相關議題，打算衝三天的session，想聽的session如下:&lt;br /&gt;&lt;br /&gt;11/2 10:30~11:20    Keynote:自由軟體與商業軟體的對話&lt;br /&gt;11/2 11:30~12:10    Keynote:SUN Microsystems&lt;br /&gt;11/2 13:00~18:00   Linux平台周邊驅動程式開發研討會&lt;br /&gt;&lt;br /&gt;11/3 10:00~12:00   COSCUP: 文字資訊處理&lt;br /&gt;11/3 13:00~16:10    COSCUP: Web Based Platform &amp;amp; COSCUP: Distributed Computing&lt;br /&gt;11/3 16:30~18:00    COSCUP: linux based laptop 與社群 &amp;amp; COSCUP: lightning talk&lt;br /&gt;&lt;br /&gt;11/4 09:10~10:40    COSCUP: 開放組織新人秀&lt;br /&gt;11/4 10:50~12:00    COSCUP: BSD&lt;br /&gt;11/4 13:00-15:00    COSCUP: 嵌入式系統 #1&lt;br /&gt;11/4 15:20-17:20     COSCUP: 嵌入式系統 #2&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-1395122013678256405?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/1395122013678256405/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=1395122013678256405' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1395122013678256405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1395122013678256405'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/icoscoscup-2007.html' title='ICOS/COSCUP 2007'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-1572241105894975795</id><published>2007-10-18T18:58:00.002+08:00</published><updated>2010-10-16T16:48:54.123+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel、list_head、doubly linked list'/><title type='text'>Linux Kernel: 強大又好用的list_head結構</title><content type='html'>程式設計者在設計一個doubly linked list時，通常會在所宣告的結構裡宣告兩個結構指標，如下所示：&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;struct student {&lt;br /&gt;    char name[16];&lt;br /&gt;    int id;&lt;br /&gt;    struct student *next, *prev;&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;只要經由prev與next兩個結構指標，便能取得該doubly linked list所有資訊。&lt;br /&gt;&lt;br /&gt;然而，Linux kernel並非引用此種作法。因此，Linux kernel定義一通用結構 (struct list_head， include/linux/list.h)，用以實作doubly linked list，此結構相當簡單，如下所示：&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;struct list_head {&lt;br /&gt;    struct list_head *next, *prev;&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;所以物件student宣告為如下：&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;struct student&lt;br /&gt;{&lt;br /&gt;    char name[16];&lt;br /&gt;    int id;&lt;br /&gt;    struct list_head list;&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;藉由list變數便能取得doubly linked list所有資訊。&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;list_head相關Marco與Function&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;這裡僅介紹較常用的macro與function，如欲進一步得知其它marco請參考include/linux/list.h&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;LIST_HEAD(name)&lt;/span&gt;&lt;br /&gt;struct list_head name = { &amp;amp;(name), &amp;amp;(name) };&lt;br /&gt;將next與prev指到自己，意味著此list為空的。&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;list_empty(const struct list_head *head)&lt;/span&gt;&lt;br /&gt;retrun head-&gt;next == head;&lt;br /&gt;檢查此list是否為空的。&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;list_add(struct list_head *new, struct list_head *head)&lt;/span&gt;&lt;br /&gt;head-&gt;next-&gt;prev = new;&lt;br /&gt;new-&gt;next = head-&gt;next;&lt;br /&gt;new-&gt;prev = head;&lt;br /&gt;head-&gt;next = new;&lt;br /&gt;將資料加入至doubly linked list最前端。建議自己動手畫個圖，便可了解這幾個指標指到何處。&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;list_del(struct list_head *entry)&lt;/span&gt;&lt;br /&gt;entry-&gt;next-&gt;prev = entry-&gt;prev;&lt;br /&gt;entry-&gt;prev-&gt;next = entry-&gt;next;&lt;br /&gt;將某一資料從中刪除。&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;list_entry(ptr,type,member)&lt;/span&gt;&lt;br /&gt;((type *)((char *)(ptr)-(unsigned long)(&amp;amp;((type *)0)-&gt;member)))&lt;br /&gt;透過此函式便能算出結構的起始位址，並做結構轉型便能取得結構的資料，此計算方式相當好用啊!!!&lt;br /&gt;以struct student為例，如下所示：&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;ol&gt;&lt;li&gt;(unsigned long)(&amp;amp;((struct student *)0)-&gt;member))) ==&gt; 計算出list成員相對位址。通常看到這一個敘述，直覺地覺得應該會記憶體區段錯誤吧 (Segmentation Fault)!? 因為該敘述用NULL的pointer存取list成員，但在(struct student *)0)-&gt;member))前面加了&amp;amp;符號，就不會發生記憶體區段錯誤。因為&amp;amp;符號，只意味著存取list的位址，而不是資料，經由此敘述便能取得list的位移植。如下圖所示，該敘述所得之位移植值為20。&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/1627618930/" title="相片分享"&gt;&lt;img src="http://farm3.static.flickr.com/2266/1627618930_f28c9895f6.jpg" alt="list_head" height="273" width="178" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li style="text-align: left;"&gt;((type *)((char *)(ptr)-(unsigned long)(&amp;amp;((type *)0)-&gt;member)))  ==&gt; 取得位移植之後，再將list的位址減去位移植，便能取得該結構的起始位址，如下圖所示 (假設結構起始位址為x)，最後再做結構轉型變大功告成。&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/adrianhuang/1627868766/" title="相片分享"&gt;&lt;img src="http://farm3.static.flickr.com/2254/1627868766_3e57720886_m.jpg" alt="list_entry" height="240" width="170" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;span style="color: rgb(51, 102, 255);"&gt;list_for_each(pos, head) &lt;/span&gt;&lt;br /&gt;for (pos = (head)-&gt;next; pos != (head); pos = pos-&gt;next)&lt;br /&gt;取得該doubly linked list所有資料。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;範例程式&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;光看這些Macro跟函式可能比較無法有sense，因此小弟寫了一簡單的程式，有興趣的可以下載此&lt;a href="http://hpds.ee.ncku.edu.tw/%7Eadrian/blog_archive/list_head_v1.tar.gz"&gt;範例程式&lt;/a&gt;玩玩看。XDD&lt;br /&gt;&lt;br /&gt;[Reference]&lt;br /&gt;&lt;a href="http://www.oreilly.com/catalog/understandlk/"&gt;&lt;span class="book-title"&gt; Understanding the Linux Kernel, Third Edition&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.kernel.org/"&gt;Linux Kernel Source Code Version 2.6.20-15&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-1572241105894975795?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/1572241105894975795/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=1572241105894975795' title='5 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1572241105894975795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1572241105894975795'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/linux-kernel-listhead.html' title='Linux Kernel: 強大又好用的list_head結構'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2266/1627618930_f28c9895f6_t.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-3225822219970750522</id><published>2007-10-12T19:35:00.000+08:00</published><updated>2007-10-12T20:09:22.692+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Vim、Plugin、C rederence manual'/><title type='text'>Vim Plugin: 好用的C函式庫參考手冊 (CRefVim)</title><content type='html'>是否曾在coding的時候，知道函式名稱卻忘了如何傳遞參數? CRefVim Plugin會是您的好幫手, 至&lt;a href="http://www.vim.org/scripts/script.php?script_id=614"&gt;Vim官網&lt;/a&gt;下載並按照齊步驟安裝，便能有此功能。&lt;br /&gt;&lt;br /&gt;功能說明&lt;br /&gt;&lt;ol&gt;&lt;li&gt;在Vim常態模式 (Normal Mode)按"\cw"，便會出現"What to lookup:"，輸入欲查詢的函式名稱。&lt;/li&gt;&lt;li&gt; 編輯一個C語言原始檔，此原始檔有memset函式，假設欲查詢memset函數說明，將游標移至memset再按\cr，就可以嚕!!&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-3225822219970750522?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/3225822219970750522/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=3225822219970750522' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3225822219970750522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/3225822219970750522'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/vim-plugin-c-crefvim.html' title='Vim Plugin: 好用的C函式庫參考手冊 (CRefVim)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-2105117864345572804</id><published>2007-10-05T16:55:00.000+08:00</published><updated>2007-10-08T15:59:41.546+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel、HZ、tick、jiffies'/><title type='text'>Linux Kernel: 簡介HZ, tick and jiffies</title><content type='html'>Linux核心幾個重要跟時間有關的名詞或變數，底下將介紹HZ、tick與jiffies。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;HZ&lt;/span&gt;&lt;br /&gt;Linux核心每隔固定週期會發出timer interrupt (IRQ 0)，HZ是用來定義每一秒有幾次timer interrupts。舉例來說，HZ為1000，代表每秒有1000次timer interrupts。HZ可在編譯核心時設定，如下所示 (以核心版本2.6.20-15為例)：&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;adrian@adrian-desktop:~$ cd /usr/src/linux&lt;br /&gt;adrian@adrian-desktop:/usr/src/linux$ make menuconfig&lt;br /&gt;Processor type and features  ---&gt; Timer frequency (250 HZ)  ---&gt;&lt;br /&gt;&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;其中HZ可設定100、250、300或1000。以小弟的核心版本預設值為250。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;小實驗&lt;/span&gt;&lt;br /&gt;觀察/proc/interrupt的timer中斷次數，並於一秒後再次觀察其值。理論上，兩者應該相差250左右。&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;adrian@adrian-desktop:~$ cat /proc/interrupts | grep timer &amp;amp;&amp;amp; sleep 1 &amp;amp;&amp;amp; cat /proc/interrupts | grep timer&lt;br /&gt;0:             &lt;span style="color: rgb(51, 102, 255);"&gt;9309306&lt;/span&gt;               IO-APIC-edge          timer&lt;br /&gt;0:                    &lt;span style="color: rgb(51, 102, 255);"&gt;9309562&lt;/span&gt;               IO-APIC-edge         timer&lt;/code&gt;&lt;/blockquote&gt;&lt;code&gt;&lt;br /&gt;上面四個欄位分別為中斷號碼、CPU中斷次數、PIC與裝置名稱。&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;問題來了，timer interrupt會做哪些事情? 答案如下所列：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;更新時間、日期與系統從開機至目前經過多少時間 。&lt;/li&gt;&lt;li&gt;更新系統資源使用率統計&lt;/li&gt;&lt;li&gt;檢查正在執行的程序是否已經超過其所分配的執行時間額度。如果是的話，則侵佔(preempt)該程序以利執行其它等待執行的程序。&lt;/li&gt;&lt;li&gt;檢查軟體時間器(Software timer，如alarm系統呼叫)跟時間延遲函式(Delay function)的延遲時間是否已經超過。&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Tick&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Tick是HZ的倒數，意即timer interrupt每發生一次中斷的時間。如HZ為250時，tick為4毫秒 (millisecond)。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Jiffies&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Jiffies為Linux核心變數(32位元變數，unsigned long)，它被用來紀錄系統自開幾以來，已經過多少的tick。每發生一次timer interrupt，Jiffies變數會被加一。值得注意的是，Jiffies於系統開機時，並非初始化成零，而是被設為-300*HZ (arch/i386/kernel/time.c)，即代表系統於開機五分鐘後，jiffies便會溢位。那溢位怎麼辦? 事實上，Linux核心定義幾個macro(timer_after、time_after_eq、time_before與time_before_eq)，即便是溢位，也能藉由這幾個macro正確地取得jiffies的內容。&lt;br /&gt;&lt;br /&gt;另外，80x86架構定義一個與jiffies相關的變數jiffies_64 ，此變數64位元，要等到此變數溢位可能要好幾百萬年。因此要等到溢位這刻發生應該很難吧。那如何經由jiffies_64取得jiffies資訊呢? 事實上，jiffies被對應至jiffies_64最低的32位元。因此，經由jiffies_64可以完全不理會溢位的問題便能取得jiffies。&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-2105117864345572804?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/2105117864345572804/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=2105117864345572804' title='6 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2105117864345572804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/2105117864345572804'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/linux-kernel-hz-tick-and-jiffies.html' title='Linux Kernel: 簡介HZ, tick and jiffies'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-6417192914590289885</id><published>2007-10-02T18:32:00.000+08:00</published><updated>2007-10-02T19:01:23.959+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux、StarDict、發音'/><title type='text'>StarDict也可發音</title><content type='html'>如同Dr.eye一樣，StarDict也可單字發音，其設定如下:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;至Sourceforge下載&lt;a href="http://downloads.sourceforge.net/stardict/WyabdcRealPeopleTTS.tar.bz2?modtime=1053377675&amp;amp;big_mirror=1"&gt;WyabdcRealPeopleTTS&lt;/a&gt;檔案&lt;/li&gt;&lt;li&gt;將WyabdcRealPeopleTTS.tar.bz2解壓縮，解壓縮會產生WyabdcRealPeopleTTS資料夾，將其資料夾移至/usr/share/即可。&lt;/li&gt;&lt;li&gt;重新啟動stardict，查詢單字看看吧!!&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;[Reference]&lt;br /&gt;&lt;a href="http://ck69user.blogspot.com/2007/01/stardict-1.html"&gt;海芋小站&lt;/a&gt; - 介紹一系列StarDict設定&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-6417192914590289885?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/6417192914590289885/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=6417192914590289885' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6417192914590289885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6417192914590289885'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/stardict.html' title='StarDict也可發音'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-7580313941570342459</id><published>2007-10-01T20:25:00.000+08:00</published><updated>2007-10-02T19:02:30.049+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vim、source file、header file、switch'/><title type='text'>Vim Tip:在原始檔與標頭檔之間切換 (Switch between source file and header file)</title><content type='html'>之前使用Anjuta有一個很方便快速鍵可以切換原始檔與標頭檔，但最近一直搜尋Vim是否也有此功能? 答案是有的，廢話不多說，設定如下：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;編輯~/.vim/ftplugin/c_extra.vim，加入底下兩行&lt;/li&gt;&lt;li&gt;nmap ,c :find %:t:r.c&lt;cr&gt;   ---&gt; 將,c對應至搜尋原始檔(也就是.c檔)&lt;/cr&gt;&lt;/li&gt;&lt;li&gt;nmap ,h :find %:t:r.h&lt;cr&gt;  ---&gt; 將,h對應至搜尋標頭檔(也就是.h檔)&lt;/cr&gt;&lt;/li&gt;&lt;/ul&gt;&lt;cr&gt;&lt;/cr&gt;&lt;cr&gt;&lt;cr&gt;&lt;/cr&gt;&lt;/cr&gt;&lt;br /&gt;如此便大功告成&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[Reference]&lt;br /&gt;&lt;a href="http://www.vim.org/tips/tip.php?tip_id=384"&gt;Vim tip website&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-7580313941570342459?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/7580313941570342459/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=7580313941570342459' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7580313941570342459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7580313941570342459'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/10/vim-tip-switch-between-source-file-and.html' title='Vim Tip:在原始檔與標頭檔之間切換 (Switch between source file and header file)'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-1863918729182183295</id><published>2007-09-07T19:31:00.000+08:00</published><updated>2007-10-17T22:45:34.082+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Trace code、Vim、Ctags、Cscope、Linux'/><title type='text'>Trace Code的好幫手: GVim+Ctags+Cscope</title><content type='html'>Trace Code的軟體舉凡&lt;a href="http://sourcenav.sourceforge.net/"&gt;Source Navigator&lt;/a&gt;與&lt;a href="http://anjuta.sourceforge.net/"&gt;Anjuta&lt;/a&gt;都佔有一定比例使用人數，但GVim+Ctags+Cscope更是一項不錯的選擇，底下將簡單介紹如何使用&lt;a href="http://ctags.sourceforge.net/"&gt;Ctags&lt;/a&gt;與&lt;a href="http://cscope.sourceforge.net/"&gt;Cscope&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Ctags&lt;br /&gt;&lt;/span&gt;Ctags用來產生原始碼每一tag(函數名或識別子)所在位置，執行Ctags會產生名為tags的檔案，Vim參考此檔便可知道每一tag的資訊。因此，只要將游標移至函數名或識別子上，按&lt;span style="color: rgb(204, 0, 0);"&gt;Ctrl+&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;]&lt;/span&gt;就可以跳至函數或識別子定義的地方。如欲返回，則按&lt;span style="color: rgb(204, 0, 0);"&gt;Ctrl+t&lt;/span&gt;即可。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cscope&lt;/span&gt;&lt;br /&gt;使用Cscope可搜尋tag、搜尋哪些地方呼叫某一函數、搜尋某一檔案與利用正規表達式搜尋相關字串等等功能 (在Vim底下按":cs"會秀出Usage Tip)。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;範例示範 (Step by Step，假設欲Trace Linux核心原始碼)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;1.  至Cscope官網下載&lt;a href="http://cscope.sourceforge.net/cscope_maps.vim"&gt;cscope_maps.vim&lt;/a&gt;，並將之複製到~/.vim/plugin/。如此便能於啟動Vim時，自動載入cscope產生出來的檔案 (cscope.out)。&lt;br /&gt;&lt;br /&gt;2. 至/usr/src/linux-source-版本編號，執行ctags與cscope兩個檔案。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;    adrian@adrian-desktop:~# cd /usr/src/linux-source-2.6.20&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;nbsp&gt;    adrian@adrian-desktop:/usr/src/linux-source-2.6.20# ctags -R &amp;amp;&amp;amp; cscope -R (ctags產生tags檔，cscope產生cscope.out) --&gt; 如欲離開cscope，按Ctrl+D即可。&lt;/nbsp&gt;&lt;/li&gt;&lt;/ul&gt;&lt;nbsp&gt;&lt;br /&gt;3. 隨便編輯一個.c檔，如init/main.c&lt;br /&gt;&lt;/nbsp&gt;    &lt;ul&gt;&lt;li&gt;&lt;nbsp&gt;adrian@adrian-desktop:/usr/src/linux-source-2.6.20# vim init/main.c&lt;/nbsp&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;nbsp&gt;假設在init/main.c想要觀看get_option這個識別子定義的地方，將游標移到該識別子上，再按&lt;span style="color: rgb(204, 0, 0);"&gt;Ctrl+&lt;/span&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;]&lt;/span&gt;。如欲知道哪些地方呼叫該識別子，將游標移到該識別子上，按Ctrl+\，再按c即可。Ctrl+\，再按s則搜尋該識別子出現的地方。&lt;/nbsp&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-1863918729182183295?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/1863918729182183295/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=1863918729182183295' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1863918729182183295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1863918729182183295'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/09/trace-code-gvimctagscscope.html' title='Trace Code的好幫手: GVim+Ctags+Cscope'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-6453692829836779825</id><published>2007-09-05T19:29:00.000+08:00</published><updated>2007-09-05T19:40:22.919+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux、Google、Google Desktop'/><title type='text'>New Google Applications for Linux coming soon!</title><content type='html'>在&lt;a href="http://linux.slashdot.org/linux/07/09/02/1956230.shtml"&gt;slashdot&lt;/a&gt;看到Google Linux用戶端服務開發團隊 (Google Linux Client Team)正在開發Linux Desktop Application，應該蠻值得期待的吧!! 更有人期待Google Talk可以運作於Linux (沒有audio/Microphone等問題)。&lt;br /&gt;&lt;br /&gt;有興趣可以看看!&lt;br /&gt;&lt;br /&gt;Related links:&lt;br /&gt;&lt;a href="http://techrythm.com/index.php/new-google-linux-apps-coming-soon/"&gt;New Google Linux Apps&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-6453692829836779825?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/6453692829836779825/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=6453692829836779825' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6453692829836779825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/6453692829836779825'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/09/new-google-applications-for-linux.html' title='New Google Applications for Linux coming soon!'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-1635629999151017868</id><published>2007-05-25T09:43:00.000+08:00</published><updated>2007-05-25T09:52:10.972+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Acrobat Reader'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu 7.04 (Feisty) + Adobe Reader 7.0</title><content type='html'>Adobe reader 7.0在Ubuntu套件庫有deb包了,  詳情參考&lt;a href="http://www.ubuntu.org.tw/modules/newbb/viewtopic.php?topic_id=4073"&gt;Ubuntu台灣官網有安裝教學&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-1635629999151017868?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/1635629999151017868/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=1635629999151017868' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1635629999151017868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/1635629999151017868'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/05/ubuntu-704-f.html' title='Ubuntu 7.04 (Feisty) + Adobe Reader 7.0'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-8688527670325813453</id><published>2007-05-16T18:48:00.000+08:00</published><updated>2007-05-16T19:05:27.855+08:00</updated><title type='text'>3D Linux Desktop --&gt; Ubuntu 7.04 + Beryl</title><content type='html'>想玩Ubuntu想了一段時間, 最近有空終於把Linux distribution從Debian換成Ubuntu, 安裝完成重開後, Ubuntu給我第一個印象當然就是介面相當友善, 且感覺Ubuntu蠻棒的, 不愧是風評相當棒的Distribution.&lt;br /&gt;&lt;br /&gt;言歸正傳, 今年四月在&lt;a href="http://osdc.tw/"&gt;OSDC.TW 2007&lt;/a&gt;遇到&lt;a href="http://yurinfore.blogspot.com/"&gt;Yuren&lt;/a&gt;, 聽Yuren說Ubuntu在安裝與設定Beryl相當容易, 前陣子索性安裝Beryl,. 如Yuren所說, apt-get一下, 使用ATI open source drvier, 外加簡單設定, Linux 3D就大功告成!&lt;br /&gt;&lt;br /&gt;底下為我的xorg.conf片段 (顯卡為 ATI Technologies Inc RV370 [Sapphire X550 Silent]&lt;br /&gt;&lt;br /&gt;Section "Module"&lt;br /&gt;        Load    "i2c"&lt;br /&gt;        Load    "bitmap"&lt;br /&gt;        Load    "ddc"&lt;br /&gt;        Load    "dri"&lt;br /&gt;        Load    "extmod"&lt;br /&gt;        Load    "freetype"&lt;br /&gt;        &lt;span style="color: rgb(255, 0, 0);"&gt;Load    "glx"&lt;/span&gt;&lt;br /&gt;        Load    "int10"&lt;br /&gt;        Load    "vbe"&lt;br /&gt;EndSection&lt;br /&gt;&lt;br /&gt;Section "ServerLayout"&lt;br /&gt;        &lt;span style="color: rgb(255, 0, 0);"&gt;Option          "AIGLX"         "true"&lt;/span&gt;&lt;br /&gt;        Identifier      "Default Layout"&lt;br /&gt;        Screen          "Default Screen"&lt;br /&gt;        InputDevice     "Generic Keyboard"&lt;br /&gt;        InputDevice     "Configured Mouse"&lt;br /&gt;        InputDevice     "stylus"        "SendCoreEvents"&lt;br /&gt;        InputDevice     "cursor"        "SendCoreEvents"&lt;br /&gt;        InputDevice     "eraser"        "SendCoreEvents"&lt;br /&gt;EndSection&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Section "Device"&lt;br /&gt;        Identifier      "ATI Technologies Inc RV370 [Sapphire X550 Silent]"&lt;br /&gt;        &lt;span style="color: rgb(255, 0, 0);"&gt;Driver          "radeon"&lt;/span&gt;&lt;br /&gt;        BusID           "PCI:1:0:0"&lt;br /&gt;EndSection&lt;br /&gt;&lt;br /&gt;Section "DRI"&lt;br /&gt;        &lt;span style="color: rgb(255, 0, 0);"&gt;Mode    0666&lt;/span&gt;&lt;br /&gt;EndSection&lt;br /&gt;&lt;br /&gt;Section "Extensions"&lt;br /&gt;        &lt;span style="color: rgb(255, 0, 0);"&gt;Option "Composite" "Enable"&lt;/span&gt;&lt;br /&gt;EndSection&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-8688527670325813453?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/8688527670325813453/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=8688527670325813453' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8688527670325813453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8688527670325813453'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/05/3d-linux-desktop-ubuntu-704-beryl.html' title='3D Linux Desktop --&gt; Ubuntu 7.04 + Beryl'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-8783863108272118380</id><published>2007-04-27T11:22:00.000+08:00</published><updated>2007-04-27T11:38:42.542+08:00</updated><title type='text'>天殺的"texlive-base-bin"</title><content type='html'>最近將Debain從lenny升級到sid遇到一個天殺的問題. 系統在設定texlive-base-bin這支程式的時候,  居然把我1G的RAM吃完, 連同我2G的Swap也全部被它給用它, 導致整個OS一直忙碌地做swap, 其設定訊息如下所示:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    Setting up texlive-base-bin (2007-5)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    Running mktexlsr. This may take some time...done&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    Building format(s) --all This may take some time.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;結果光build format就花了4、5個小時還是沒做完. 因此, 索性將RAM升級到2G, 結果還是一樣, 2G RM吃完, 接著再把2G swap也用完, 且讓它跑了一整個晚上 (將近12小時), 結果還是沒build完. So, you don't just take some time. You certainly take a long long time! Goddamned!&lt;br /&gt;&lt;br /&gt;  哀....現在我的debian已經被我搞爛. 看來現在是轉戰Ubuntu的時候了, 之前看到[&lt;a href="http://yurinfore.blogspot.com/"&gt;Yuren&lt;/a&gt;]在玩Ubuntu, 想說有時間一定要玩玩看, 反正都要重灌了, 乾脆完Ubuntu看看好了!&lt;a href="http://yurinfore.blogspot.com/"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-8783863108272118380?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/8783863108272118380/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=8783863108272118380' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8783863108272118380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/8783863108272118380'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/04/texlive-base-bin.html' title='天殺的&quot;texlive-base-bin&quot;'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-4633300541436485142</id><published>2007-04-26T10:42:00.002+08:00</published><updated>2011-01-13T16:50:41.981+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gpg'/><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='apt-key'/><title type='text'>debian NO_PUBKEY error</title><content type='html'>Debian或Unbuntu使用者在更新套件往往都會出現類似&lt;span class="postbody"&gt;NO_PUBKEY xxxxxxxxxxxx的錯誤訊息, 此代表使用的public key已逾期或有&lt;/span&gt;&lt;span class="postbody"&gt;新加入 apt 的 source 但未下載該對應之公開金鑰, 目前的解法是利用gpg程式到key server下載該key, 例如:&lt;/span&gt;&lt;span class="postbody"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;&lt;br /&gt;$ sudo &lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;gpg&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; --keyserver hkp://wwwkeys.eu.pgp.net --recv-keys xxxxxxxxxxxxxxxx&lt;/span&gt;&lt;span class="postbody"&gt;     &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    $&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; sudo &lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;gpg --armor --export xxxxxxxxxxxxxxxx | apt-key add -&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;如此便解決該問題,  但就小弟所上班公司的網路只能從port 80出去, 上面之方法似乎沒辦法解決 (被firewall擋掉, 底下提供一簡單的方法:&lt;br /&gt;1. 首先, 先到key server網站[&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 255, 255);font-family:Geneva,Arial;" &gt;&lt;b&gt;&lt;a href="http://wwwkeys.eu.pgp.net/"&gt;SURFnet Public Key Infrastructure&lt;/a&gt;]&lt;/b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;下載&lt;/span&gt;&lt;/span&gt;&lt;span class="postbody"&gt;公開金鑰, 例如:欲搜尋 公開金鑰為A70DAF536070D3A1, 因此就在&lt;/span&gt;&lt;span style="font-family:Geneve,Arial;"&gt;"Search String"文字方塊鍵入"0x&lt;/span&gt;&lt;span class="postbody"&gt;A70DAF536070D3A1", 並下載存為key.txt&lt;br /&gt;&lt;br /&gt;2. 使用apt-key程式手動加入&lt;/span&gt;&lt;span class="postbody"&gt;A70DAF536070D3A1之&lt;/span&gt;&lt;span class="postbody"&gt;公開金鑰&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;    $ sudo apt-key add key.txt&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;3. 大功告成&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="postbody"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;$ sudo apt-get update&lt;/span&gt; --&gt; 應該就可以了!!&lt;br /&gt;&lt;br /&gt;[參考文獻]&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;a style="font-weight: bold; color: rgb(51, 51, 255);" class="maintitle" href="http://moto.debian.org.tw/viewtopic.php?t=11404&amp;amp;start=0&amp;amp;postdays=0&amp;amp;postorder=asc&amp;amp;highlight=gpg"&gt;APT 系統的金鑰管理機制簡介&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-4633300541436485142?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/4633300541436485142/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=4633300541436485142' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4633300541436485142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/4633300541436485142'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/04/debian-nopubkey-error.html' title='debian NO_PUBKEY error'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594360167010513475.post-7545588615244092709</id><published>2007-04-09T14:25:00.000+08:00</published><updated>2007-04-09T14:41:51.159+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='smart phone'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><title type='text'>基於Linux平台的智慧型手機</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;blockquote&gt;&lt;/blockquote&gt;   最近看到一支以Linux(採用&lt;a href="http://www.openmoko.org/"&gt;OpenMoko&lt;/a&gt;)為平台的smartphone手機, 其手機由大眾電腦所開發, 型號為Neo 1973, 感覺介面還蠻friendly, 且又號稱hackable. 讚!!!&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;參考:&lt;br /&gt;  &lt;a href="http://www.linuxdevices.com/news/NS2986976174.html"&gt;LinuxDevices&lt;/a&gt;&lt;br /&gt;  &lt;a href="http://www.jollen.org/blog/2006/11/mobile_20_openmoko_linux_smart.html"&gt;Jollen大Blog&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594360167010513475-7545588615244092709?l=adrianhuang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://adrianhuang.blogspot.com/feeds/7545588615244092709/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594360167010513475&amp;postID=7545588615244092709' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7545588615244092709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594360167010513475/posts/default/7545588615244092709'/><link rel='alternate' type='text/html' href='http://adrianhuang.blogspot.com/2007/04/linux.html' title='基於Linux平台的智慧型手機'/><author><name>Adrian Huang (黃圳柏)</name><uri>http://www.blogger.com/profile/05200420228495783060</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://farm2.static.flickr.com/1204/1482361249_366a410514_t.jpg'/></author><thr:total>0</thr:total></entry></feed>
