<?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-3519606278200777308</id><updated>2011-07-31T10:49:11.605+08:00</updated><category term='vt'/><category term='egl'/><category term='binder'/><category term='x11'/><category term='link script'/><category term='adb'/><category term='graphics'/><category term='wayland'/><category term='eagle'/><category term='i915'/><category term='x86'/><category term='tty'/><category term='algorithm'/><category term='dri'/><category term='一千零一夜'/><category term='bit counting'/><category term='console'/><category term='android'/><category term='cursor'/><category term='opengl'/><category term='mesa'/><category term='gem'/><category term='keysym'/><category term='kernel'/><category term='keyboard'/><category term='qemu'/><category term='firmware'/><category term='objdump'/><category term='initcall'/><category term='dri2'/><category term='objcopy'/><category term='cairo'/><category term='disassembly'/><category term='bitbake'/><category term='loader'/><title type='text'>olv</title><subtitle type='html'>Time flies</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-5158650122475466580</id><published>2009-12-25T16:22:00.003+08:00</published><updated>2009-12-25T17:04:31.601+08:00</updated><title type='text'>Android with 3D Effects</title><content type='html'>年終了。&lt;br /&gt;&lt;br /&gt;最近幾個月不知道為什麼，沒辦法專心工作。利用上 ptt 跟看漫畫的空檔，把說很久的特效弄出可以 demo 的樣子&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/pIBHQiqcdTM&amp;hl=en_US&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/pIBHQiqcdTM&amp;hl=en_US&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;感謝 &lt;a href="http://i-miss-erin.blogspot.com/"&gt;Erin&lt;/a&gt; 的幫忙，這段影片展示了 Cube 跟 Fire 特效。 WindowManagerService 允許的地方都可以接特效，但現在只有接在程式啟動時。&lt;br /&gt;&lt;br /&gt;目前的進展可以在 &lt;a href="http://gitorious.org/android-eeepc/base/commits/effects"&gt;gitorious&lt;/a&gt; 上取得。不過很顯然地，還有很多東西要弄。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-5158650122475466580?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/5158650122475466580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=5158650122475466580' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/5158650122475466580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/5158650122475466580'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/12/android-with-3d-effects.html' title='Android with 3D Effects'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-8399514397848466099</id><published>2009-11-29T22:54:00.007+08:00</published><updated>2009-11-30T01:09:46.174+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorithm'/><category scheme='http://www.blogger.com/atom/ns#' term='bit counting'/><title type='text'>Fast bit counting</title><content type='html'>最近 mesa3d-dev mailing list 有一個討論串在討論 &lt;a href="http://sourceforge.net/mailarchive/message.php?msg_name=1259431876.2186.19.camel%40ztoshiba"&gt;bit counting&lt;/a&gt;，也就是在算一個 unsigned int 裡有幾個 bit 是 1。&lt;br /&gt;&lt;br /&gt;假設 unsigned int 有 32 bits 寬，最簡單的算法就是一個迴圈跑 32 次，一個一個 bit 去看。想當然這不是有效率的算法。事實上，只要做&lt;a href="http://cgit.freedesktop.org/mesa/mesa/commit/?id=c93dcbfea7b8e1cd0f14a96bc466419bdce7eb30"&gt;簡單的修改&lt;/a&gt;，就可以讓迴圈跑的次數降到跟 bit 為 1 的 bit 數相同。換句話說，如果 unsigned int 裡只有 3 個 bit 為 1，迴圈只要跑三次就可以。不過像這麼基礎的運算，一定有不少人下過功夫在找最快的算法。一個問題，工程師會去尋找更好的方法；但是身為鄉民，我們感興趣的只有最好的方法，而且我們從不自己找！很幸運地，在最開頭提到的討論串裡頭，就有人提出一個號稱最快的算法。&lt;br /&gt;&lt;br /&gt;討論串中提到的方法經過簡化可以寫成&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;int bitcount(unsigned int v)&lt;br /&gt;{&lt;br /&gt;    v = v - ((v &gt;&gt; 1) &amp; 0x55555555);&lt;br /&gt;    v = (v &amp; 0x33333333) + ((v &gt;&gt; 2) &amp; 0x33333333);&lt;br /&gt;    v = (v + (v &gt;&gt; 4)) &amp; 0x0f0f0f0f;&lt;br /&gt;    return (v * 0x01010101) &gt;&gt; 24;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;在深入去看這段程式碼前，最好可以用抽像點的方式看它想做的事&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_e4cXiDy19_c/SxKSioeSxzI/AAAAAAAAAeE/U43pm2Kg8IY/s1600/bitcount1.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 125px;" src="http://1.bp.blogspot.com/_e4cXiDy19_c/SxKSioeSxzI/AAAAAAAAAeE/U43pm2Kg8IY/s400/bitcount1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5409547226103072562" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;上圖中，v0 是使用者的輸入。展開成二進位表示法，每個 bit 的值不是 1 就是 0。如果有一個方法可以讓所有的 bit 變成兩個兩個一組 (v1)、4 個 4 個一組 (v2)、8 個 8 個一組 (v3)、一直到 32 個 bit 自己成一組 (v5)，那 v5 的值剛好就是我們要的結果。從 v4 看起，假設我們已經有 v4 了，那麼應該不難發現&lt;br /&gt;&lt;pre class="programlisting"&gt;v5 = (v4 &amp; 0xffff) + (v4 &gt;&gt; 16);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;以此類推，很快就可以發現我們需要的是&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;int bitcount2(unsigned int v)&lt;br /&gt;{&lt;br /&gt;    v = (v &amp; 0x55555555) + ((v &gt;&gt;  1) &amp; 0x55555555); /* v1 */&lt;br /&gt;    v = (v &amp; 0x33333333) + ((v &gt;&gt;  2) &amp; 0x33333333); /* v2 */&lt;br /&gt;    v = (v &amp; 0x0f0f0f0f) + ((v &gt;&gt;  4) &amp; 0x0f0f0f0f); /* v3 */&lt;br /&gt;    v = (v &amp; 0x00ff00ff) + ((v &gt;&gt;  8) &amp; 0x00ff00ff); /* v4 */&lt;br /&gt;    v = (v &amp; 0x0000ffff) + ((v &gt;&gt; 16) &amp; 0x0000ffff); /* v5 */&lt;br /&gt;    return v;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;這時再回過頭去看 bitcount，可以注意到雖然算法不完全相同，但它前三行在做的也是求 v1、v2 與 v3。但它接下來不是求 v4，而是把 v3 乘上 0x01010101。透過四則運算，這個乘法可以改寫成加法&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;v = (v3 &lt;&lt; 24) + (v3 &lt;&lt; 16) + (v3 &lt;&lt; 8) + v3&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;把 v3 的展開式代入，會發現&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_e4cXiDy19_c/SxKY3Cqq6hI/AAAAAAAAAeM/FNfZSallgVk/s1600/bitcount2.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 29px;" src="http://3.bp.blogspot.com/_e4cXiDy19_c/SxKY3Cqq6hI/AAAAAAAAAeM/FNfZSallgVk/s400/bitcount2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5409554173801458194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;將這個結果向右 shift 24 bits 得到的也是 v5。這就是 bitcount 的做法。&lt;br /&gt;&lt;br /&gt;如果把寫死的 magic number 換成適當型別的除法與補數運算，這個 bitcount 函數對 32/64/128-bits 寬的 unsigned int 都可以適用。寬度的限制是來自於 v4' 的第一個小括號，它不能大於或等於 2^8。不過如果 bitcount 求到 v4 再來做乘法，這個限制也可以被放寬。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-8399514397848466099?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/8399514397848466099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=8399514397848466099' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/8399514397848466099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/8399514397848466099'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/11/fast-bit-counting.html' title='Fast bit counting'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_e4cXiDy19_c/SxKSioeSxzI/AAAAAAAAAeE/U43pm2Kg8IY/s72-c/bitcount1.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-3424484427468314864</id><published>2009-06-25T10:47:00.006+08:00</published><updated>2009-06-25T15:19:58.445+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='一千零一夜'/><category scheme='http://www.blogger.com/atom/ns#' term='dri'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='dri2'/><category scheme='http://www.blogger.com/atom/ns#' term='i915'/><category scheme='http://www.blogger.com/atom/ns#' term='gem'/><title type='text'>一千零一夜之 GEM Object</title><content type='html'>&lt;blockquote&gt;這個系列是讀書筆記，作者可能沒有跟主題有關的開發經驗。&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;GEM object 是一種 buffer，一種可以在 A 程式被配置，在 B 程式被使用的 buffer。當 userspace 產生一個 GEM object 時，以 i915 為例，它會呼叫 drm_gem_object_alloc。從這個函數的頭幾行&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;struct drm_gem_object *obj;&lt;br /&gt;&lt;br /&gt;BUG_ON((size &amp; (PAGE_SIZE - 1)) != 0);&lt;br /&gt;&lt;br /&gt;obj = kcalloc(1, sizeof(*obj), GFP_KERNEL);&lt;br /&gt;&lt;br /&gt;obj-&gt;dev = dev;&lt;br /&gt;obj-&gt;filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);&lt;br /&gt;if (IS_ERR(obj-&gt;filp)) {&lt;br /&gt;    kfree(obj);&lt;br /&gt;    return NULL;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;可以看出，它只是一塊 shared memory。就這個方式來看，GEM object 其實不是新的東西。&lt;br /&gt;&lt;br /&gt;但這塊 buffer 除了 A、B 程式會用到外，它還另外有一個使用者，這個使用者是 GPU。之所以把 shared memory 包裝成 GEM object 最主要的原因是，kernel 需要同步 CPU 和 GPU 對這塊 buffer 的存取。很明顯地，如果讓 CPU 與 GPU 同時寫入同一塊記憶體，出來的結果一定無法預期。在 GEM object 裡，處理同步的方法是引入 domain 的機制。所有人在存取 GEM object 前，必須先把它的 domain 設好。如果是 GPU 要讀取或寫入，那就需要先把 read domain 或 write domain 設成 GPU；相對的，如果是 CPU 要讀取或寫入，則需要把 read/write domain 設成 CPU。DRM 保證的是，只要正確地指定 domain，存取到的資料也會是正確的。&lt;br /&gt;&lt;br /&gt;為了解 domain 跟同步的關係，我們可以看一下當我們把 read domain 指定為 CPU 時，kernel 會幫我們做什麼處理。這部份完整的程式碼可以在 i915_gem_object_set_to_cpu_domain 看到。&lt;br /&gt;&lt;br /&gt;首先，kernel 要確定之前所下的 GPU 指令已經全部執行完畢，而且 GPU cache 要 flush 掉&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;i915_gem_object_flush_gpu_write_domain(obj);&lt;br /&gt;ret = i915_gem_object_wait_rendering(obj);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;GPU 的運作方式是會依序執行某個指定的 ring buffer 裡面的指令，而開發者要做的是把指令放到這個 buffer。為了達到目的，kernel 會在 ring buffer 最後加上 flush 跟 interrupt 指令，並且開始等待中斷。我們可以想像，當 kernel 收到中斷時，也就表示之前的指令都已經執行，包含它自己加上的 flush 指令。&lt;br /&gt;&lt;br /&gt;事實上，CPU 除了直接存取 shared memory 外，也可以從 AGP aperture 去存取，這在 i915 裡稱做 GTT domain。所以 kernel 也要確定這邊沒有資料被 cache 住&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;i915_gem_object_flush_gtt_write_domain(obj);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;這些動作可能造成記憶體上的資料被改變，而，這時候 CPU 還不知道這件事。所以只要再確保 CPU 可以知道這些變動&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;i915_gem_object_set_to_full_cpu_read_domain(obj);&lt;br /&gt;if ((obj-&gt;read_domains &amp; I915_GEM_DOMAIN_CPU) == 0) {&lt;br /&gt;    i915_gem_clflush_object(obj);&lt;br /&gt;    obj-&gt;read_domains |= I915_GEM_DOMAIN_CPU;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;我們就可以說 GEM object 已經被移到 CPU read domain。&lt;br /&gt;&lt;br /&gt;GEM object 是 shared memory 的特性，讓 X server 可以直接把 buffer 傳給 client 做 DRI。它同時也可以當做到 OpenGL 裡頭各種 buffer object 的 storage。除了 Intel 外，在 2.6.31 也可以看到初步的 &lt;a href="http://airlied.livejournal.com/66958.html"&gt;ATI Radeon KMS&lt;/a&gt; 支援。雖然從使用者的經驗來看，似乎只是進入另一個黑暗時期。但是在&lt;a href="http://keithp.com/blogs/Sharpening_the_Intel_Driver_Focus/"&gt;領袖&lt;/a&gt;的帶領下，我們好像也可以看到光了！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-3424484427468314864?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/3424484427468314864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=3424484427468314864' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/3424484427468314864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/3424484427468314864'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/06/gem-object.html' title='一千零一夜之 GEM Object'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-2188939344472562860</id><published>2009-06-24T10:10:00.004+08:00</published><updated>2009-06-24T12:10:28.473+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='一千零一夜'/><category scheme='http://www.blogger.com/atom/ns#' term='firmware'/><category scheme='http://www.blogger.com/atom/ns#' term='loader'/><category scheme='http://www.blogger.com/atom/ns#' term='link script'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='initcall'/><title type='text'>一千零一夜之 Kernel and Firmware</title><content type='html'>&lt;blockquote&gt;這個系列是讀書筆記，作者可能沒有跟主題有關的開發經驗。&lt;/blockquote&gt;&lt;br /&gt;Driver 需要 firmware 時會呼叫 request_firmware，這個函數會在 /sys 底下產生適當的裝置讓 userspace 上傳 firmware 給 driver。它會等到 firmware 上傳完成 (或發生錯誤) 才回傳。除了建立適當的裝置，它也會送一個 uevent，內容類似&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;KERNEL[1245809267.000297] add      /devices/pci0000:00/0000:00:1c.2/0000:02:00.0/firmware/0000:02:00.0 (firmware)&lt;br /&gt;UDEV_LOG=3&lt;br /&gt;ACTION=add&lt;br /&gt;DEVPATH=/devices/pci0000:00/0000:00:1c.2/0000:02:00.0/firmware/0000:02:00.0&lt;br /&gt;SUBSYSTEM=firmware&lt;br /&gt;FIRMWARE=iwlwifi-3945-2.ucode&lt;br /&gt;SEQNUM=1226&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;uevent 事件通常是 udev 在處理，在遇到 firmware 事件，也就是 SUBSYSTEM 是 firmware 的事件時，udev 預設會執行 /lib/udev/firmware.agent (在 Debian 上) 來上傳 firmware。簡化過的 firmware.agent 其實只做了&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;echo 1 &gt; /sys/$DEVPATH/loading # 準備上傳&lt;br /&gt;cat $firmwaredir/$FIRMWARE &gt; /sys/$DEVPATH/data&lt;br /&gt;echo 0 &gt; /sys/$DEVPATH/loading # 上傳完畢&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;注意到上面大寫的變數內容都是 uevent 提供，像是 $DEVPATH 就是 kernel 剛產生用來接受 firmware 上傳的虛擬裝置。&lt;br /&gt;&lt;br /&gt;這是 firmware 擺在 filesystem 上的情形。當 CONFIG_FIRMWARE_IN_KERNEL 打開時，如果 driver 被編進 kernel，firmware 也會一起被編進去。在 request_firmware 中有一段&lt;br /&gt;&lt;br /&gt;&lt;pre class="programlisting"&gt;for (builtin = __start_builtin_fw; builtin != __end_builtin_fw;&lt;br /&gt;     builtin++) {&lt;br /&gt; if (strcmp(name, builtin-&gt;name))&lt;br /&gt;  continue;&lt;br /&gt; dev_info(device, "firmware: using built-in firmware %s\n",&lt;br /&gt;   name);&lt;br /&gt; firmware-&gt;size = builtin-&gt;size;&lt;br /&gt; firmware-&gt;data = builtin-&gt;data;&lt;br /&gt; return 0;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;會先檢查 driver 要求的 firmware 是否有內建。這邊的 __start_builtin_fw 與 __end_builtin_fw 是 link time 產生的 symbol，所以不會在任何 C code 找到它們的定義。在 vmlinux.lds (或 include/asm-generic/vmlinux.lds.h) 可以看到，它們的值會是所有 .builtin_fw section 內容的開始位址與結束位址。&lt;br /&gt;&lt;br /&gt;.builtin_fw 的內容要再找到 firmware/Makefile。在那份 Makefile 可以看到 kbuild 會為每一個要內建的 firmware 產生一份 assembly code。這些 assembly code 編出來的 object code 會跟 kernel link 在一起，達成 firmware 內建的目的。從 assembly code 可以看出，這些 object code 的內容會是 firmware 本身，以及一個放在 .builtin_fw section 的資料結構，給出 firmware 的檔名、位置、還有大小。&lt;br /&gt;&lt;br /&gt;這邊看到內建 firmware 的做法其實是 kernel 常見的手法之一。寫 driver 最開始會加的 module_init(entry_point) 是另一個例子。這些 macro 會產生 initcall，而所有的 initcall 在 link time 也是用類似的方式被收集。在電腦剛開機進 userspace 前它們會依照被收集的順序依序被執行。這邊可以看到一個要注意的小地方。在每個 subsystem (rtc, scsi, ...) 的 Makefile 中，核心的部份必須放在 driver 之前。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-2188939344472562860?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/2188939344472562860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=2188939344472562860' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/2188939344472562860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/2188939344472562860'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/06/kernel-and-firmware.html' title='一千零一夜之 Kernel and Firmware'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-2301888890767785777</id><published>2009-06-09T18:14:00.003+08:00</published><updated>2009-06-09T18:33:06.352+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eagle'/><category scheme='http://www.blogger.com/atom/ns#' term='opengl'/><category scheme='http://www.blogger.com/atom/ns#' term='mesa'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android Wave</title><content type='html'>&lt;a href="http://olvaffe.blogspot.com/2009/06/android-3d-acceleration-on-x86.html"&gt;上篇文章&lt;/a&gt;提到的程式碼已上線，有興趣的朋友可以到 &lt;a href="http://gitorious.org/android-eeepc/pages/Home"&gt;Android Eee PC&lt;/a&gt; 專案網頁下載。&lt;br /&gt;&lt;br /&gt;在做 clean build 的空檔，請 &lt;a href="http://jeremyone.blogspot.com/"&gt;Jeremy&lt;/a&gt; 幫忙錄了一段影片，以證明加速是真的 XD&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/ricl2Kg3pMI&amp;hl=zh_TW&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/ricl2Kg3pMI&amp;hl=zh_TW&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;不過錄到後半，我頭暈得差點連瀏覽器 icon 在哪都找不到，所以請注意不要靠太近看。再來兩天要參加 &lt;a href="http://freedomhectaipei.pbworks.com/"&gt;FreedomHEC Taipei 2009&lt;/a&gt;，順便休息一下。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-2301888890767785777?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/2301888890767785777/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=2301888890767785777' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/2301888890767785777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/2301888890767785777'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/06/android-wave.html' title='Android Wave'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-1464029571177623521</id><published>2009-06-04T17:49:00.002+08:00</published><updated>2009-06-04T18:39:23.471+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dri'/><category scheme='http://www.blogger.com/atom/ns#' term='eagle'/><category scheme='http://www.blogger.com/atom/ns#' term='opengl'/><category scheme='http://www.blogger.com/atom/ns#' term='gem'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android 3D acceleration on x86</title><content type='html'>過去一、二個月的文章都是圍繞著 android x86 與 mesa/dri 在打轉，原因無它，因為這陣子在做的事恰好就是 Android 在 Eee PC 上的 3D 加速。因為 android 跟 mesa 都是第一次接觸，所以確實費了不少工夫在認識它們。&lt;br /&gt;&lt;br /&gt;Android 在起來的時候，會試著載入 /system/lib 底下的 libagl.so 與 libhgl.so。前者是 OpenGL ES 與 EGL 的純軟體實作，source code 在 frameworks/base/opengl/libagl/ 底下；後者則與硬體相關，目前沒有開放的實作。所以我做的事基本上就是寫一份 libhgl.so。&lt;br /&gt;&lt;br /&gt;之前在 &lt;a href="http://olvaffe.blogspot.com/2009/04/dri2-overview.html"&gt;DRI Overview&lt;/a&gt; 有提到，只要有適當的 loader，DRI driver 可以在 X 以外的平台使用。目前我的 libhgl.so 實作是基於 &lt;a href="http://cgit.freedesktop.org/~krh/eagle/"&gt;eagle&lt;/a&gt;，並只支援 intel graphics chipsets。因為 i915_dri.so 實作了 OpenGL，而不是 OpenGL ES，所以定點數與部份 ES 才有的 extension 沒有辦法支援。這個問題最快的解決方式應該是改用 Gallium 搭配 &lt;a href="http://zrusin.blogspot.com/2009/05/opengl-es.html"&gt;OpenGL ES state tracker&lt;/a&gt;，這也是接下來要評估的。&lt;br /&gt;&lt;br /&gt;對 Android 本身，主要則有三個部份需要修改。一是 EGLDisplaySurface 要用 kernel modesetting 的實作取代，同時 kernel 也要上 2.6.29；二是 GPUHardware 要改用 i915 的 GEM object 實作；三是 Surface 要能認得 GEM object。&lt;br /&gt;&lt;br /&gt;目前整個 Android 系統可以正常運作。SurfaceFlinger 或一些 3D 軟體像是 &lt;a href="http://code.google.com/p/android-gl/"&gt;Android-GL&lt;/a&gt; 也可以正確地被加速。不過目前的實作比較接近於驗證這個方式的可行性。程式碼整理好後會放在 &lt;a href="http://gitorious.org/android-eeepc"&gt;Android Eee PC&lt;/a&gt;，到時有興趣的開發者都可以一同參與。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-1464029571177623521?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/1464029571177623521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=1464029571177623521' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/1464029571177623521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/1464029571177623521'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/06/android-3d-acceleration-on-x86.html' title='Android 3D acceleration on x86'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-5381752706266573184</id><published>2009-05-15T15:39:00.006+08:00</published><updated>2009-05-15T17:06:48.938+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='graphics'/><category scheme='http://www.blogger.com/atom/ns#' term='eagle'/><category scheme='http://www.blogger.com/atom/ns#' term='mesa'/><category scheme='http://www.blogger.com/atom/ns#' term='cairo'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android Window System</title><content type='html'>在上星期 &lt;a href="http://0xlab.org/"&gt;0xlab&lt;/a&gt; 的討論會中，我對 Android 的視窗系統做了簡短的分享，投影片可以在&lt;a href="http://people.debian.org.tw/~olv/surfaceflinger/surfaceflinger.pdf"&gt;這邊&lt;/a&gt;取得。簡報內容主要在介紹 SurfaceManager，同時也附上簡短的&lt;a href="http://people.debian.org.tw/~olv/surfaceflinger/demo.tar.gz"&gt;範例程式&lt;/a&gt;，示範利用 Android 的 native library 取得可用來繪圖的記憶體。&lt;br /&gt;&lt;br /&gt;之前的&lt;a href="http://olvaffe.blogspot.com/2009/04/android-binder.html"&gt;文章&lt;/a&gt;提到 Android 跟 &lt;a href="http://cairographics.org/"&gt;cairo&lt;/a&gt; 的結合，也是利用一樣的方法，麻煩的地方反而是在於 cairo 的編譯。我當時是照著 cairo (與 pixman) 的 Makefile.am 寫一份 Android.mk，非常的苦。jserv 後來提到了 &lt;a href="http://plausible.org/andy/agcc"&gt;agcc&lt;/a&gt;，或許可以拿來與既有程式的 autotools 結合。&lt;br /&gt;&lt;br /&gt;不過苦也有苦的好處，因為苦慣了就不會害怕。不小心還會弄出怪怪的東西&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/dgrzLViKFT0&amp;hl=zh_TW&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/dgrzLViKFT0&amp;hl=zh_TW&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&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/3519606278200777308-5381752706266573184?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/5381752706266573184/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=5381752706266573184' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/5381752706266573184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/5381752706266573184'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/05/android-window-system.html' title='Android Window System'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-4142266401889557529</id><published>2009-04-29T11:31:00.008+08:00</published><updated>2009-04-29T12:05:40.850+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='一千零一夜'/><category scheme='http://www.blogger.com/atom/ns#' term='dri'/><category scheme='http://www.blogger.com/atom/ns#' term='eagle'/><category scheme='http://www.blogger.com/atom/ns#' term='dri2'/><category scheme='http://www.blogger.com/atom/ns#' term='opengl'/><category scheme='http://www.blogger.com/atom/ns#' term='egl'/><category scheme='http://www.blogger.com/atom/ns#' term='mesa'/><category scheme='http://www.blogger.com/atom/ns#' term='gem'/><title type='text'>一千零一夜之 eagle</title><content type='html'>&lt;blockquote&gt;這個系列是讀書筆記，作者可能沒有跟主題有關的開發經驗。&lt;/blockquote&gt;&lt;br /&gt;之前的&lt;a href="http://olvaffe.blogspot.com/2009/04/dri2-overview.html"&gt;文章&lt;/a&gt;提到過，只要有適當的 loader，DRI driver 也可以用在 X server 以外的平台，eagle 就是一個例子。eagle 提供開發者接近於 &lt;a href="http://www.khronos.org/egl/"&gt;EGL&lt;/a&gt; 的 API，並且可以運作在支援 DRI2 的 X server 與支援 GEM 的 intel drm 之上。這篇文章主要想討論後者。&lt;br /&gt;&lt;br /&gt;eagle 與視窗系統無關的實作，行數落在大約 800 行左右。intel drm 的支援也只在 250 行左右。對它使用到的技術有些許了解後，只要花一個晚上就可以讀完，算是學習 linux 3D 實作不錯的途徑。也因為它的簡單，閱讀過程如果有難以理解的部份，也可以馬上修改跑跑看。如果這兩部份看完後想要再看 DRI2 的部份，eagle 也可以讓人滿足。&lt;br /&gt;&lt;br /&gt;intel drm 的支援在 eagle 中稱為 backend，以 EagleBackend 表示。Backend 與視窗系統相關，要提供的主要功能有&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;建立 EGLSurface&lt;/li&gt;&lt;br /&gt;&lt;li&gt;提供 DRI driver 需要的 GEM buffer&lt;/li&gt;&lt;br /&gt;&lt;li&gt;更新畫好的內容到螢幕上&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;intel drm backend 建立 EGLSurface 的函數是 intelCreateSurfaceForName。這邊的 name 型別為 uint32_t，指的是 GEM buffer 的 identifier。如果沒給的話，backend 會產生一塊新的 buffer。client 可以要求 double buffering，這時 surface 的 backBuffer 會設為 EGL_TRUE。&lt;br /&gt;&lt;br /&gt;intelGetBuffers 負責提供 DRI driver 需要的 GEM buffer，像是 front buffer，back buffer 或 depth buffer 等。這邊要特別注意，在 double buffering 的情形，也就是 backBuffer 設為 EGL_TRUE 的時候，即便 DRI driver 要求了 front buffer，intelGetBuffers 還是會產生新的 buffer 回傳給 DRI driver，而不是回傳 intelCreateSurfaceForName 時給定或產生的 front buffer。這個新產生的 buffer 也被稱為 fake front buffer。&lt;br /&gt;&lt;br /&gt;最後看到 intelSwapBuffers，也就是 eglSwapBuffers 會呼叫的函數。可以看到，當不是 double buffering 時，這個函數會直接 return，因為 DRI driver 本來就是畫在真正的 front buffer 上。若是 double buffering 的話，intelSwapBuffers 會把 DRI driver 以為的 (fake) front buffer 複製到真正的 front buffer 上。&lt;br /&gt;&lt;br /&gt;Backend 大致上就處理這些事情。eagle 的核心則負責提供接近 EGL 的 API。它同時也是 DRI loader，選定適當的 EagleBackend 並載入適當的 DRI driver。除了選擇與 dlopen 適當的 .so 檔外，核心其餘的程式碼大多在處理 EGL 的型別與 DRI 型別的對映。這個部份很基礎，也是所有想寫 loader 的開發者都要熟悉的東西。這邊的程式碼比較直接，有興趣的人可以自行閱讀。&lt;br /&gt;&lt;br /&gt;在初次研讀 eagle 的過程中，我最感興趣的其實是這篇文章沒提到的 glapi。這是 mesa 或 mesa 自動產生的程式碼，其中後者佔了絕大多數。在許多功用中，其中一項功用是提供 OpenGL (ES) 的 global symbols，讓 link 到 libeagle.so 的程式可以呼叫 gl* 等函數。這可以算是 mesa build system 的一部份，對熟悉 linux 3D 的組成有相當的幫助。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-4142266401889557529?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/4142266401889557529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=4142266401889557529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/4142266401889557529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/4142266401889557529'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/04/eagle.html' title='一千零一夜之 eagle'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-600647139721281450</id><published>2009-04-17T13:53:00.009+08:00</published><updated>2009-04-17T14:13:23.937+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='一千零一夜'/><category scheme='http://www.blogger.com/atom/ns#' term='binder'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>一千零一夜之 Android Binder</title><content type='html'>&lt;blockquote&gt;這個系列是讀書筆記，作者可能沒有跟主題有關的開發經驗。&lt;/blockquote&gt;&lt;br /&gt;Binder 是 android 大量使用的 IPC 機制。當使用者在 launcher (home) 按了某個 App 時，這個動作會經由 ActivityManager 向 zygote 發出請求，並從 zygote fork 出新的 process 執行被選擇的 App。這個過程大致上有 4 個 process 參與：home、system server、zygote 和新產生的 appA。更仔細去看的話，&lt;ol&gt;&lt;br /&gt;&lt;li&gt;system server 向 home 送出 touchscreen 事件&lt;/li&gt;&lt;br /&gt;&lt;li&gt;home 向 system server 送出 start activity 事件&lt;/li&gt;&lt;br /&gt;&lt;li&gt;system server 向 zygote 送出 appA 的啟動參數&lt;/li&gt;&lt;br /&gt;&lt;li&gt;appA 向 system server 送出 attach 事件&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;除了第 3 項以外，其它跨 process 的溝通都是採用 binder。Zygote 是 android 上少數幾個聽 unix socket 的程式。驗證這個說法最簡單的方法是去看 process 的 memory maps 還有 opened fd，這個技巧在&lt;a href="http://olvaffe.blogspot.com/2008/12/dri.html"&gt;之前&lt;/a&gt;有用過，這邊暫且略過。&lt;br /&gt;&lt;br /&gt;一個 IPC 機制的效能很大一部份取決於它資料交換的能力，從這點去切入是不錯的途徑。所有參與 binder 的 process 都會在一開始向 /dev/binder 裝置 mmap 一塊 read-only 的記憶體，大小在幾個 MB 左右。A process 傳送資料給 B process 的做法是，由 A 對 /dev/binder 做 ioctl 將資料先送給 binder driver。依資料大小，binder driver 動態配置足夠的 physical memory 存放來自 A 的資料，並在 B 一開始 mmap 得到的 address space 裡尋找一段足夠大且未使用的 address area。找到後，binder driver 會修改 B 的 page table，讓這段 address area 映射到剛剛動態配置的 physical memory。如此一來，B 可以直接存取 A 送過來的資料；等到 B 不需要這些資料時，再由 B 負責把這塊記憶體還回去給系統。這段實作可以參改 binder driver 的 binder_update_page_range 函數。&lt;br /&gt;&lt;br /&gt;Process 對 binder 的操作只透過 ioctl 做 buffer 的讀寫。Buffer 的內容是一系列的 (command, argument) 組。每個 command 為 4 bytes，argument 的長度視 command 而定，可能是固定的，也可能是變動的。當 A 跟 B 交換資料時，通常會由一方送出 BC_TRANSACTION command，再由另一方回覆 BC_REPLY command。Transaction/reply 的 argument 除了一段 header 外，其餘的資料部份會使用上一段討論的方式做交換。資料的長度跟內容由 A、B 另行約定，可能是整數、浮點數或字串等。除了上述的基本資料型別外，還有三種用 struct flat_binder_object 表示的特殊型別：BINDER、HANDLE、FD。FD 型別讓 A、B 可以交換 file descriptor，也就是說，A 可以打開某個檔案，把 fd 傳給 B，讓 B 去讀寫。或者說，也是更重要的，surface manager 可以準備一塊 surface，把 surface 的 fd (一塊 ashmem 記憶體) 傳給一個 app，讓 app 可以在上面作畫。有了這層理解，我們對 android 可以有更自由的發揮，例如，可以不改一行 cairo 的程式碼，就利用 cairo 與 c++ 寫出一個會動的時鐘：&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_e4cXiDy19_c/Segbbj69YWI/AAAAAAAAATY/6o-POqzF5jo/s1600-h/android-cairo.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 309px;" src="http://2.bp.blogspot.com/_e4cXiDy19_c/Segbbj69YWI/AAAAAAAAATY/6o-POqzF5jo/s400/android-cairo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5325536719678562658" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;回到正題，我們知道 binder 還有 BINDER 與 HANDLE 這兩個特殊型別。它們的功用可以用 service port 跟 connection 做類比。就像 httpd 可以開 80 port 提供服務，client 可以跟它建立 connection 使用服務一樣，在 android 上頭，WindowManagerService 可能建立了一個 BINDER，提供了視窗操作的服務。其它程式可能會建立這個服務的 HANDLE。在 binder 之上，android 提供了 aidl 讓開發者可以把 remote service 當做 local object 操作，所以開發者可以直接呼叫 mWindowManager.setRotation 來旋轉螢幕，而幾乎可以不用知道 BINDER 跟 HANDLE 的存在。&lt;br /&gt;&lt;br /&gt;當一個 process 收到 transaction 的時候，如果 binder driver 發現 process 沒有任何 thread 已經準備好等著要處理，等到下次有 thread 來處理時，它會收到 BR_SPAWN_LOOPER 的訊息，userspace 也會多產生一個 thread 專門對 /dev/binder 做 I/O，確保下次有 transaction 的時候，有比較高的機會是已經有 thread 準備好了。提個數字，在 android sdk 1.5 preview 的 emulator 剛開好機時，在我的機器上，Phone App 會有 11 個 thread，而其中有 6 個 thread 是跑在同一個迴圈裡等著對 /dev/binder 做 I/O。這項機制相信是為了縮短應用程式的反應時間。&lt;br /&gt;&lt;br /&gt;Binder 再探討下去還有許多東西可以討論，例如 android native library 沒有 aidl 可以用，它如何建立操作 binder 的物件？或者 native code 裡面常常看到的 sp&lt;&gt;、wp&lt;&gt; 跟 binder 的 reference counting 關係為何？對 binder 的功能有初步認識後，再去理解這些實作會顯得直覺許多。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-600647139721281450?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/600647139721281450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=600647139721281450' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/600647139721281450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/600647139721281450'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/04/android-binder.html' title='一千零一夜之 Android Binder'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_e4cXiDy19_c/Segbbj69YWI/AAAAAAAAATY/6o-POqzF5jo/s72-c/android-cairo.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-2949663241802476533</id><published>2009-04-09T03:19:00.009+08:00</published><updated>2009-04-09T03:36:17.473+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='x86'/><category scheme='http://www.blogger.com/atom/ns#' term='cursor'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android with cursor</title><content type='html'>一般 PC 上面沒有 touchscreen 只有滑鼠，為了方便做事，晚上試著幫 Android 加上 cursor：&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/YgmsLJswq50&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en&amp;feature=player_embedded&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/YgmsLJswq50&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en&amp;feature=player_embedded&amp;fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;暫時是做在 WindowManagerService 裡面，髒髒的 patch 可以在&lt;a href="http://people.debian.org.tw/~olv/android/dirty-software-cursor.patch"&gt;這邊&lt;/a&gt;取得。目前 drag 有點問題，而且是 software cursor，歡迎有興趣的網友幫忙改進 :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-2949663241802476533?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/2949663241802476533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=2949663241802476533' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/2949663241802476533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/2949663241802476533'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/04/android-with-cursor.html' title='Android with cursor'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-1088307287311855269</id><published>2009-04-06T01:02:00.005+08:00</published><updated>2009-04-06T02:00:31.983+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='一千零一夜'/><category scheme='http://www.blogger.com/atom/ns#' term='dri'/><category scheme='http://www.blogger.com/atom/ns#' term='dri2'/><category scheme='http://www.blogger.com/atom/ns#' term='opengl'/><category scheme='http://www.blogger.com/atom/ns#' term='mesa'/><category scheme='http://www.blogger.com/atom/ns#' term='gem'/><title type='text'>一千零一夜之 DRI2 Overview</title><content type='html'>&lt;blockquote&gt;這個系列是讀書筆記，作者可能沒有跟主題有關的開發經驗。&lt;/blockquote&gt;&lt;br /&gt;Linux 的圖形加速一直是個問題，不過這個問題在最近幾版的 kernel 隱約可以看到一些希望。從 2.6.28 的 GEM memory manager 到 2.6.29 的 kernel modesetting，由 Intel 與 RedHat 的開發者所提出的加速架構已經進入 kernel，雖然目前採用這些架構的只有 Intel 自身的驅動程式，但其它繪圖晶片的 open source 驅動程式勢必也得跟隨此架構。在 Intel 與 AMD 相繼釋出 datasheet 後，或許有天所有的使用者都可以享用這些成果，不再依賴私有的驅動程式。&lt;br /&gt;&lt;br /&gt;去年年中 GEM 公佈後，許多架構迅速翻新，DRI2 最後也環繞著 GEM 在設計。DRI (Direct Rendering Infrastructure) 是各家 open source 驅動程式所依循的架構，雖然處處都可以看見這個名詞，但是要了解它背後的實作卻不太容易。困難的地方在於 DRI 的組成份子很多，而且大部份來頭都不小。以 Intel 的 945GM 為例，在 kernel 有 drm.ko 與 i915.ko 兩個模組，對映到 userspace，有 drm 提供的libdrm.so 與 libdrm_intel.so；在 xserver 有 libglx.so 與 libdri2.so 這兩個 extension，以及 xf86-video-intel 提供的 intel_drv.so；最後在 mesa 也有 libGL.so 以及 i915_dri.so。習慣上，intel_drv.so 被稱作 2D driver 或 DDX driver，i915_dri.so 則是 3D driver 或 DRI driver。從一個 3D 程式被執行時到顯示在螢幕上，參與這個看似普通的過程背後就是上面這些檔案。&lt;br /&gt;&lt;br /&gt;DRI 最重要的內涵在於，一個 X client 可以向 X server 取得視窗的 buffer(s)，並利用硬體加速在上面直接繪圖，不再透過 X server。Kernel 在 DRI 扮演的主要角色是讓多個 process 可以共享 (GEM) buffer，還有接受與執行 process 傳來的硬體指令。這邊困難的地方之一在於 CPU 跟 GPU 都有各自的 MMU 與 cache，所以有許多同步的問題要處理。&lt;br /&gt;&lt;br /&gt;libGL.so 在 DRI 架構裡扮演了 loader 的角色，它跑在 client 這邊。就像 OpenGL 與平台無關一樣，DRI driver 也與平台無關。loader 一方面載入 DRI driver，一方面又提供適當的 hook 讓 DRI driver 呼叫，並實作了平台相關的部份。所以在 DRI driver 真的要用到 buffer 的時候，它會呼叫 loader 的 getBuffers 函數取得視窗的 buffer 與大小。libglx.so 跟 libdri2.so 實作了 GLX 與 DRI2 這兩個 X extensions。在 X 的平台上，對於 DRI driver 的要求，libGL.so 會利用 GLX 與 DRI2 協定取得所需的資訊，並傳回給 DRI driver。&lt;br /&gt;&lt;br /&gt;一個快速驗證上面說法的方法是直接檢視系統的 /usr/lib/libGL.so 跟 /usr/lib/dri/i915_dri.so。libGL.so 只是 loader，檔案大小應該要比 i915_dri.so 小不少；而 i915_dri.so 與平台無關，所以 ldd 應該不會看到 X11 的函式庫。如果再進一步想，那是不是只要提供適當的 loader，DRI driver 也能用在 X 以外的平台？答案是肯定的。&lt;br /&gt;&lt;br /&gt;在 compiz 剛出來的時候，有很多名詞跟著它一起冒出來。像是 XGL、GLX_EXT_texture_from_pixmap、還有 AIGLX 等。在 libGL.so 無法成功跟 X server 溝通使用 DRI 時，client 的 3D 繪圖指令會改經由 GLX 傳給 server 處理，這被稱作 indirect rendering。在早先，libglx.so 會利用純軟體的方式執行這些 3D 指令，所以 indirect rendering 跟 software rendering 是等價的。這個情形在 AIGLX 引入後有很大的改變。在 AIGLX 下，libglx.so 除了提供 GLX extension 實作外，它同時也是一個 DRI loader，可以利用 DRI driver 進行 3D 加速。因為 AIGLX，indirect rendering 不再直接被視為慢、無法接受，雖然它還是多了 client 到 server 的 overhead。AIGLX 即是 Accelerated Indirect GLX 的縮寫，非常直接。&lt;br /&gt;&lt;br /&gt;因為我直接從 DRI2 開始看，無法比較它跟 DRI1 的差異。在 DRI2 作者 Kristian Høgsberg 的 &lt;a href="http://hoegsberg.blogspot.com/"&gt;blog&lt;/a&gt; 可以找到一些關鍵字。Kristian Høgsberg 同時也是&lt;a href="http://olvaffe.blogspot.com/2009/03/wayland.html"&gt;之前文章&lt;/a&gt;提到的 Wayland 的作者。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-1088307287311855269?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/1088307287311855269/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=1088307287311855269' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/1088307287311855269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/1088307287311855269'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/04/dri2-overview.html' title='一千零一夜之 DRI2 Overview'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-5181150537331821457</id><published>2009-03-23T15:09:00.009+08:00</published><updated>2009-03-23T18:08:39.716+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='qemu'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='adb'/><title type='text'>Android on x86</title><content type='html'>因為之後的需要，這兩天開始看起 android，尤其是在 x86 的情境。不過手邊沒有硬體可以用，打算先用模擬器測試。可能是 cupcake 在我動工的前兩天 &lt;a href="http://www.mail-archive.com/android-framework@googlegroups.com/msg01736.html"&gt;merge 到 master&lt;/a&gt; 時的部份變更，雖然很快就編好 image，可以進到 console，但是 UI 起不來。又多花了一天時間才順利完工。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_e4cXiDy19_c/Scc5OroqVXI/AAAAAAAAARw/uWDEDpjFd0c/s1600-h/Screenshot-QEMU.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 309px;" src="http://2.bp.blogspot.com/_e4cXiDy19_c/Scc5OroqVXI/AAAAAAAAARw/uWDEDpjFd0c/s400/Screenshot-QEMU.png" alt="" id="BLOGGER_PHOTO_ID_5316280809528382834" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在 android 的 &lt;a href="http://source.android.com/download"&gt;Get source&lt;/a&gt; 頁面有編譯 ARM 版本的方式。關於 android on x86，最重要的參考資料則是 &lt;a href="http://groups.google.com/group/android-porting/browse_thread/thread/66862bdb52dac936/1ae192cee32eaa71"&gt;這個討論串&lt;/a&gt;，利用 google 也可以找到更詳細的步驟。前面提到的 cupcake merge 同時造成了 opencore 的編譯問題，解法一樣要去看最開頭提到的 &lt;a href="http://www.mail-archive.com/android-framework@googlegroups.com/msg01736.html"&gt;merge 到 master&lt;/a&gt; 討論串。不過我在 Debian testing (AMD64) 上做的時候，還需要先找到 build/core/combo/linux-x86.mk 的這兩行&lt;br /&gt;&lt;pre class="programlisting"&gt;$(combo_target)GLOBAL_CFLAGS := $($(combo_target)GLOBAL_CFLAGS) -m32&lt;br /&gt;$(combo_target)GLOBAL_LDFLAGS := $($(combo_target)GLOBAL_LDFLAGS) -m32&lt;/pre&gt;&lt;br /&gt;把 -m32 參數拿掉，然後再多安裝 {gcc,g++}-multilib 套件。前者是說不要把 host binary 預設編成 32bit，後者則是讓某些在 Android.mk 又加上 -m32 的模組可以編譯成功。&lt;br /&gt;&lt;br /&gt;一開始我是用 VirtualBox 2.1.4，不過因為 UI 起不來，想要用 adb 來除錯，所以後來改用 QEMU 0.10.0 (x86 版)，並利用它的 -redir 功能讓 host 可以 adb 進去模擬出來的機器。給 QEMU 用的 kernel 有幾件事要注意一下：為方便起見，最好把&lt;br /&gt;&lt;pre class="programlisting"&gt;CONFIG_NE2K_PCI=y&lt;br /&gt;CONFIG_FB_VESA=y&lt;br /&gt;CONFIG_FRAMEBUFFER_CONSOLE=y&lt;/pre&gt;&lt;br /&gt;直接編進 kernel，並設定 vga=xxx。如果 kernel 跑到一半停住，並且在倒數幾行出現&lt;br /&gt;&lt;pre class="programlisting"&gt;MP-BIOS bug: 8254 timer not connected to IO-APIC&lt;/pre&gt;&lt;br /&gt;訊息，可以在 cmdline 加上 noapic 參數解決。&lt;br /&gt;&lt;br /&gt;前面一直提到的 UI 問題可以參考這個 &lt;a href="http://people.debian.org.tw/%7Eolv/android/qemu-x86-dirty-fix-after-cupcake-merged.patch"&gt;dirty patch&lt;/a&gt; 做修改。這樣應該就完成了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-5181150537331821457?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/5181150537331821457/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=5181150537331821457' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/5181150537331821457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/5181150537331821457'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/03/android-on-x86.html' title='Android on x86'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_e4cXiDy19_c/Scc5OroqVXI/AAAAAAAAARw/uWDEDpjFd0c/s72-c/Screenshot-QEMU.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-774917533869028366</id><published>2009-03-01T22:09:00.008+08:00</published><updated>2009-03-23T18:09:07.621+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='x11'/><category scheme='http://www.blogger.com/atom/ns#' term='dri2'/><category scheme='http://www.blogger.com/atom/ns#' term='gem'/><category scheme='http://www.blogger.com/atom/ns#' term='wayland'/><title type='text'>編譯 Wayland</title><content type='html'>&lt;a href="http://groups.google.com/group/wayland-display-server"&gt;Wayland&lt;/a&gt; 是一個極精簡的 display server。它是由 &lt;a href="http://hoegsberg.blogspot.com/"&gt;Kristian Høgsberg&lt;/a&gt; 在工作之餘所進行的實驗性計畫。與 X server 不同，Wayland client 要負責所有的繪圖動作，server 只處理最後的合成與顯示。這邊的繪圖動作還包含視窗邊框，這在 X 的世界裡是由 window manager 完成。&lt;br /&gt;&lt;br /&gt;client 必須把它想顯示的畫面畫在 GEM buffer 上。GEM buffer 是 kernel 在管理的資源，它在不同的時間點可能會存在於不同的地方，例如它可能在系統記憶體或者是顯示卡的記憶體上。client 想要繪圖時可以利用 mmap 取得 GEM buffer 的指標，直接對它進行操作。client 與 server 的資料交換，圖形以外的部份是透過 unix socket；圖形部份因為使用 GEM buffer，server 可以直接取得。server 最後再透過 compositor 把 client 的畫面合成並顯示到螢幕上。&lt;br /&gt;&lt;br /&gt;Wayland 還在早期的階段，這邊提到的編譯方法可能很快就不適用 (或被簡化)。編譯 Wayland 之所以困難，主要原因在於它用到的 git repository 不好找。先讓我們找到 DRM 並且安裝起來&lt;br /&gt;&lt;pre class="programlisting"&gt;$ git clone git://anongit.freedesktop.org/git/mesa/drm&lt;br /&gt;$ cd drm&lt;br /&gt;$ ./autogen.sh --prefix=/opt/gfx&lt;br /&gt;$ make&lt;br /&gt;$ make install&lt;br /&gt;$ export PKG_CONFIG_PATH=/opt/gfx/lib/pkgconfig&lt;br /&gt;$ export LD_LIBRARY_PATH=/opt/gfx/lib&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;再來安裝 Mesa 跟 DRI driver (這邊選用 i915)&lt;br /&gt;&lt;pre class="programlisting"&gt;$ git clone git://anongit.freedesktop.org/git/mesa/mesa&lt;br /&gt;$ cd mesa&lt;br /&gt;$ git remote add krh git://people.freedesktop.org/~krh/mesa&lt;br /&gt;$ git fetch krh&lt;br /&gt;$ git checkout -b eagle krh/eagle&lt;br /&gt;$ ./autogen.sh --prefix=/opt/gfx --with-dri-drivers=i915 \&lt;br /&gt; --disable-gallium --disable-glw --disable-glut --disable-glu \&lt;br /&gt; --without-demos&lt;br /&gt;$ make&lt;br /&gt;$ make install&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Wayland 會用到 udev 136 之後提供的 libudev，雖然這邊只安裝 libudev，但要注意它可能會覆蓋系統上本來的檔案&lt;br /&gt;&lt;pre class="programlisting"&gt;$ git clone git://git.kernel.org/pub/scm/linux/hotplug/udev.git&lt;br /&gt;$ cd udev&lt;br /&gt;$ ./autogen.sh&lt;br /&gt;$ cd udev/lib&lt;br /&gt;$ make&lt;br /&gt;$ make install&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Wayland 目前的 compositor 是採用 eagle 這個 EGL 實作&lt;br /&gt;&lt;pre class="programlisting"&gt;$ git clone git://anongit.freedesktop.org/~krh/eagle&lt;br /&gt;$ cd eagle&lt;br /&gt;$ autoreconf -vif&lt;br /&gt;$ ./configure --prefix=/opt/gfx&lt;br /&gt;$ make&lt;br /&gt;$ make install&lt;br /&gt;$ export EAGLE_DRIVER_PATH=/opt/gfx/lib/dri&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;大部份的 example client 用到了 cairo-drm，這是一個直接以 GEM buffer 為 surface backend 的 cairo 分支&lt;br /&gt;&lt;pre class="programlisting"&gt;$ git clone git://anongit.freedesktop.org/git/cairo&lt;br /&gt;$ cd cairo&lt;br /&gt;$ git remote add ickle git://anongit.freedesktop.org/~ickle/cairo&lt;br /&gt;$ git fetch ickle&lt;br /&gt;$ git checkout -b drm ickle/drm&lt;br /&gt;$ ./autogen.sh --prefix=/opt/gfx --disable-xlib&lt;br /&gt;$ make&lt;br /&gt;$ make install&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;最後，Wayland&lt;br /&gt;&lt;pre class="programlisting"&gt;$ git clone git://people.freedesktop.org/~krh/wayland.git&lt;br /&gt;$ cd wayland&lt;br /&gt;$ autoreconf -vif&lt;br /&gt;$ ./configure --prefix=/opt/gfx&lt;br /&gt;$ make&lt;br /&gt;$ make install&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Wayland 需要 kernel modesetting 的支援 (linux kernel &gt;= 2.6.29)。再克服這一關，一個晚上折騰的結果&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_e4cXiDy19_c/Saqs-xyXuCI/AAAAAAAAAMc/7WZZ51NVWm4/s1600-h/wayland-screenshot-0.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 250px;" src="http://3.bp.blogspot.com/_e4cXiDy19_c/Saqs-xyXuCI/AAAAAAAAAMc/7WZZ51NVWm4/s400/wayland-screenshot-0.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5308245305326024738" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-774917533869028366?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/774917533869028366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=774917533869028366' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/774917533869028366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/774917533869028366'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/03/wayland.html' title='編譯 Wayland'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_e4cXiDy19_c/Saqs-xyXuCI/AAAAAAAAAMc/7WZZ51NVWm4/s72-c/wayland-screenshot-0.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-3060005505437810861</id><published>2009-02-27T22:44:00.007+08:00</published><updated>2009-02-27T23:03:09.499+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='objdump'/><category scheme='http://www.blogger.com/atom/ns#' term='disassembly'/><category scheme='http://www.blogger.com/atom/ns#' term='objcopy'/><title type='text'>objdump 反組譯</title><content type='html'>objdump 反組譯是一個很實用的功能，但有時候我們拿到的不是執行檔，而是 binary image 或者是自行從記憶體 dump 下來的內容。在這種情況，要手動給 objdump 足夠的資訊，它才能完成它的工作。事實上，它需要的只是簡單的：&lt;br /&gt;&lt;pre class="programlisting"&gt;$ arm-angstrom-linux-gnueabi-objdump -b binary -m arm -D bootrom.bin&lt;/pre&gt;&lt;br /&gt;或者也可以先利用 objcopy 將 binary image 轉成 ELF 格式：&lt;br /&gt;&lt;pre class="programlisting"&gt;$ arm-angstrom-linux-gnueabi-objcopy -I binary -O elf32-littlearm -B arm --rename-section .data=.text bootrom.bin bootrom.elf&lt;/pre&gt;&lt;br /&gt;這樣也可以照本來的習慣去使用 objdump。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-3060005505437810861?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/3060005505437810861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=3060005505437810861' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/3060005505437810861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/3060005505437810861'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/02/objdump.html' title='objdump 反組譯'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-8220645104399351671</id><published>2009-01-30T13:59:00.009+08:00</published><updated>2009-01-30T15:09:16.556+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='一千零一夜'/><category scheme='http://www.blogger.com/atom/ns#' term='tty'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='vt'/><category scheme='http://www.blogger.com/atom/ns#' term='console'/><title type='text'>一千零一夜之 Console I/O</title><content type='html'>&lt;blockquote&gt;這個系列是讀書筆記，作者可能沒有跟主題有關的開發經驗。&lt;/blockquote&gt;&lt;br /&gt;當一個程式被執行時，它的 stdin/stdout/stderr 會從父程序繼承。如果沒有特別指定，它們通常會指向同一個諸如 /dev/ttyX 或 /dev/pts/X 的 TTY device。很難不去好奇，當我們 getchar() 或 printf() 時，對一個 TTY device 的 I/O，在 kernel 裡頭會發生什麼事？&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_e4cXiDy19_c/SYKlg_es3nI/AAAAAAAAALg/HlpFXRZyJ08/s1600-h/tty.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 167px;" src="http://4.bp.blogspot.com/_e4cXiDy19_c/SYKlg_es3nI/AAAAAAAAALg/HlpFXRZyJ08/s400/tty.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5296978097955724914" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;口語裡的 console，指的通常是圖中 VT。VT 是 virtual terminal 的縮寫，對 userspace 來說，它就像是一部真實存在著的終端機；在 kernel 裡頭，VT（的功能之一）是一個 TTY driver，它是所有 /dev/ttyX 裝置的驅動程式。對 TTY device 的 I/O 動作，會經由 TTY core 送給 TTY driver。資料往來於 TTY 與 TTY driver 的過程中，或者說圖中連結 TTY 與 VT 的線，被稱做 TTY ldisc，TTY line discipline。&lt;br /&gt;&lt;br /&gt;在&lt;a href="http://olvaffe.blogspot.com/2009/01/keyboard-in-console.html"&gt;之前的文章&lt;/a&gt;中我們看到鍵盤向 TTY 送出的資料。來自於鍵盤的輸入，可能是特別的按鍵組合，目的並不是讓 userspace 去取得這些輸入。例如，我們會敲下 Ctrl-C 來中斷目前的程式；Ctrl-Z 來暫停目前的程式。又或者，我們不希望輸入的密碼會出現在螢幕上。這些需求都在 line discipline 中被滿足。因為所有的 I/O 都會經由 line discipline，於是它可以在使用者輸入特定字元時，對目前的程式送出 SIGINT 或 SIGTSTP；它也可以選擇是否要把使用者的輸入再 echo 回 VT。從這邊也可以看到，line discipline 不只可以對資料做緩衝與處理，它還被允計針對特定的輸入做特定的行為。當我們從 VT 換到實體的 COM port 時，且當與 COM port 連結的裝置不是終端機，而是數據機時，line discipline 甚至可以拒絕所有來自 userspace 的 I/O，轉而從 PPP network device 與 userspace 做資料交換。實際上，TTY device 只是一個 transport layer，可以跟它連結的裝置千變萬化。line discipline 於是也被設計成可以抽換；當從終端機換成數據機時，line discipline 也從 N_TTY 換成 N_PPP。&lt;br /&gt;&lt;br /&gt;跟來自鍵盤的輸入一樣，使用者對 TTY device 寫入的資料，會經過 line discipline，VT，再進入螢幕。在 drivers/char/n_tty.c 的 do_output_char 函數中&lt;br /&gt;&lt;pre class="programlisting"&gt;switch (c) {&lt;br /&gt;...&lt;br /&gt;case '\r':&lt;br /&gt; if (O_ONOCR(tty) &amp;amp;&amp;amp; tty-&gt;column == 0)&lt;br /&gt;  return 0;&lt;br /&gt; if (O_OCRNL(tty)) {&lt;br /&gt;  c = '\n';&lt;br /&gt;  if (O_ONLRET(tty))&lt;br /&gt;   tty-&gt;canon_column = tty-&gt;column = 0;&lt;br /&gt;  break;&lt;br /&gt; }&lt;br /&gt; tty-&gt;canon_column = tty-&gt;column = 0;&lt;br /&gt; break;&lt;br /&gt;case '\t':&lt;br /&gt; spaces = 8 - (tty-&gt;column &amp;amp; 7);&lt;br /&gt; if (O_TABDLY(tty) == XTABS) {&lt;br /&gt;  if (space &lt;&gt;column += spaces;&lt;br /&gt;  tty-&gt;ops-&gt;write(tty, "        ", spaces);&lt;br /&gt;  return spaces;&lt;br /&gt; }&lt;br /&gt; tty-&gt;column += spaces;&lt;br /&gt; break;&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;可以看到 line discipline 會對特殊字元，像是換行符號或 tab 等做排版。更多關於 N_TTY 這個 line discipline 的功能可以參考 stty(1)。&lt;br /&gt;&lt;br /&gt;VT 的架構與實體的 terminal 與 host computer 架構是對應的。要把現在手上正在上網的電腦想像成它是 terminal 與 host computer 的組成可能不是那麼容易。一個相對常見、具體的情境，是用一條線把手上的電腦與 wifi router 或手機的 UART console 連結。上圖中的 Computer B 可以理解成手上的電腦，Computer A 則是跑著 linux 的嵌入式系統。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-8220645104399351671?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/8220645104399351671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=8220645104399351671' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/8220645104399351671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/8220645104399351671'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/01/console-io.html' title='一千零一夜之 Console I/O'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_e4cXiDy19_c/SYKlg_es3nI/AAAAAAAAALg/HlpFXRZyJ08/s72-c/tty.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-7531134001303714390</id><published>2009-01-27T11:21:00.004+08:00</published><updated>2009-01-27T11:37:40.780+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='一千零一夜'/><category scheme='http://www.blogger.com/atom/ns#' term='keyboard'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='keysym'/><category scheme='http://www.blogger.com/atom/ns#' term='console'/><title type='text'>一千零一夜之 keyboard in console</title><content type='html'>&lt;blockquote&gt;這個系列是讀書筆記，作者可能沒有跟主題有關的開發經驗。&lt;/blockquote&gt;&lt;br /&gt;按下或放開按鍵的時候，鍵盤會產生一段長度不等的 scancode，這段 scancode 會被 keyboard driver (像是 drivers/input/keyboard/atkbd.c) 處理，轉換成類型為 EV_MSC 與 EV_KEY 的 input event。EV_MSC 事件的內容是 scancode 本身，與硬體直接相關且不容易處理，除非有特殊需求，通常我們比較關心的是 EV_KEY input event。想要處理這些事件的其它子系統，可以向 input layer 註冊 input handler。例如 evdev 會註冊一個 input handler 讓 userspace 可以從 /dev/input/eventX 直接取得鍵盤事件。kernel 的 console driver 也會向 input layer 註冊一個 handler 來取得鍵盤事件，這是我們這次想要比較深入了解的項目。&lt;br /&gt;&lt;br /&gt;console 跟鍵盤的交互作用可以在 drivers/input/char/keyboard.c 看到。在 console 底下，鍵盤有四種模式，&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;#define VC_XLATE        0 /* translate keycodes using keymap */&lt;br /&gt;#define VC_MEDIUMRAW    1 /* medium raw (keycode) mode */&lt;br /&gt;#define VC_RAW          2 /* raw (scancode) mode */&lt;br /&gt;#define VC_UNICODE      3 /* Unicode mode */&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;可以利用 kbd_mode 命令來切換。前面有提到 keyboard driver 會送出 EV_MSC 與 EV_KEY 兩種 input event，其中前者送出的 scancode 被用來實作 VC_RAW 模式；後者送出的 keycode，則可以用來實作 VC_MEDIUMRAW 模式。剩下的兩種模式都是 keycode 的再加工。&lt;br /&gt;&lt;br /&gt;scancode 到 keycode 的轉換透過了 keyboard driver 定義的 keycode table 完成。在 atkbd.c 裡，如果忽略掉其它細節，它只是簡單的&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;keycode = atkbd-&gt;keycode[code];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;一行程式碼。有些多媒體鍵盤會有一些按鍵的 scancode 不在預設的 keycode table 裡，當這些按鍵被按下或放開的時候，kernel 會印出類似&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;atkbd.c: Unknown key pressed (translated set 2, code 0x1e on isa0060/serio0).&lt;br /&gt;atkbd.c: Use 'setkeycodes 1e &amp;lt;keycode&amp;gt;' to make it known.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;的訊息。依照這段訊息提示的方法去做&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;# setkeycodes &amp;lt;scancode&amp;gt; &amp;lt;keycode&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;就可以新增一筆對映的資料。setkeycodes 與 getkeycodes 命令即是用來設定或取得目前的 keycode table。值得注意的是，大部份的 keycode 有對應的 symbolic name，例如 keycode 30 的 symbolic name 是 KEY_A，keycode 48 的是 KEY_B，keycode 46 的是 KEY_C 等 (見 /usr/include/linux/input.h)。這些 symbolic name 是照美式鍵盤定義而來，拿到其它語言的鍵盤上並沒有意義。&lt;br /&gt;&lt;br /&gt;console 下 keyboard 預設的模式是 VC_XLATE 或 VC_UNICODE。從 input layer 拿到 keycode 後，console 會呼叫 kbd_event 函數做處理。在這兩個模式下，keycode 會被轉換成 keysym&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;key_map = key_maps[shift_final];&lt;br /&gt;...&lt;br /&gt;keysym = key_map[keycode];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;然後 queue 到 console buffer。stdin 接到 console 的程式即是由這邊取得使用者的輸入。這個動作會經過 line discipline，不過我們這邊不去討論。&lt;br /&gt;&lt;br /&gt;一個 keysym 是兩個 byte，分別可以由 KTYP(keysym) 跟 KVAL(keysym) 取得它的 type 與 value。當 type 小於 0xf0 時，整個 keysym 代表一個 UCS2 的 codepoint，keysym 會被轉成 UTF-8 放進 console buffer；當 type &gt;= 0xf0 時，與 type 相關的 handler 被呼叫，其 prototype 為&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,&lt;br /&gt;       char up_flag);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;其中 value 就是剛剛看到的 KVAL(keysym)。有些 handler 會把處理過的 value 寫入 console buffer，有些則不會，這樣設計的目的以例子來看最容易理解。我們知道 shift 按著的時候，所有的字母大小寫會互換。當 shift 的按下時，鍵盤控制器送出中斷，keyboard driver 收到後把 scancode 讀出並轉成 keycode，送出 input event。console 收到 event 後利用 keymap 把 keycode 轉成 keysym。shift 的 keysym type 是 0xf7，value 是 0x00，送到對應的 handler 中&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;if (up_flag) {&lt;br /&gt; if (shift_down[value])&lt;br /&gt;  shift_down[value]--;&lt;br /&gt;} else&lt;br /&gt; shift_down[value]++;&lt;br /&gt;&lt;br /&gt;if (shift_down[value])&lt;br /&gt; shift_state |= (1 &lt;&lt; value);&lt;br /&gt;else&lt;br /&gt; shift_state &amp;= ~(1 &lt;&lt; value);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;可以發現 shift_state 的第一個 bit 被設為 1。shift_state 是 keyboard.c 裡的 file-scope 變數，當任何一個按鍵再被按下時，kbd_event 裡這一段程式碼&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;shift_final = (shift_state | kbd-&gt;slockstate) ^ kbd-&gt;lockstate;&lt;br /&gt;key_map = key_maps[shift_final];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;選取了不同的 keymap，導致或許不一樣的 keysym 被送出，本來是小寫的英文字母也因而變成大寫。&lt;br /&gt;&lt;br /&gt;在 kernel 內部實作，console 使用的是 UCS2 編碼。不管是使用者列印到 console 的字串，或者是 keysym 的 value 都會先重新編碼成 UCS2 再做進一步處理。在 VC_UNICODE 模式底下，UCS2 會以 UTF-8 形式被送進 console buffer；在 VC_XLATE 模式，則會嘗試再編碼回原來的 value 送到 console buffer。&lt;br /&gt;&lt;br /&gt;相對於 keymap 複雜的機制，它的操作卻非常簡單。在 userspace 可以利用 loadkeys 與 dumpkeys 命令來操作 keymaps&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# loadkeys de # 使用德式鍵盤 layout&lt;br /&gt;# loadkeys us # 使用美式鍵盤 layout&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;進一步的資訊可以參考 keymaps(5)。&lt;br /&gt;&lt;br /&gt;這篇文章我們看到了鍵盤在 console 的運作。如果換到 X(org) server，情形有點不同，而且也因驅動程式而異。例如 xf86-input-keyboard 雖然是從 console 取得鍵盤事件，但它會把 console 設為 VC_RAW 模式，自行處理 scancode。而 xf86-input-evdev 則是直接從 /dev/input/eventX 取得鍵盤事件。以後有機會也可以看看 X(org) 下的鍵盤運作。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-7531134001303714390?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/7531134001303714390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=7531134001303714390' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/7531134001303714390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/7531134001303714390'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2009/01/keyboard-in-console.html' title='一千零一夜之 keyboard in console'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-8475741387939745595</id><published>2008-12-26T00:44:00.022+08:00</published><updated>2008-12-26T16:23:25.367+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='一千零一夜'/><category scheme='http://www.blogger.com/atom/ns#' term='bitbake'/><title type='text'>一千零一夜之 BitBake Data class</title><content type='html'>&lt;blockquote&gt;這個系列是讀書筆記，作者可能沒有跟主題有關的開發經驗。&lt;/blockquote&gt;&lt;br /&gt;曾經使用過 &lt;a href="http://www.openembedded.org/"&gt;OpenEmbedded&lt;/a&gt; 的開發者應該可以想像，當 bitbake my-app 被執行時，它會去做哪些事。例如，它可能會去讀 conf 檔，然後利用這資料 (e.g., PREFERRED_PROVIDER of my-app) 決定要用哪個 bb 檔。當然 bb 檔可能會 inherit 某個 class 檔或者 include 某個 inc 檔。等到需要的資料都讀進來了，bitbake 就可以開始 unpack、pack、configure 等去逐一執行這個 bb 檔所指定的各 task。如果暫時不去理會 cache、相依性或者某 bb 檔指定的某檔案是怎麼抓下來，這個想像也就是 bitbake 核心的功能之一，也是這篇文章感興趣的項目：BitBake Data class。&lt;br /&gt;&lt;br /&gt;以 glib-2.0-native_2.16.1.bb 為例，&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;require glib-2.0_${PV}.bb&lt;br /&gt;&lt;br /&gt;FILESPATH = "${FILE_DIRNAME}/glib-2.0-${PV}:${FILE_DIRNAME}/files"&lt;br /&gt;DEPENDS = "gtk-doc-native"&lt;br /&gt;PR = "r2"&lt;br /&gt;&lt;br /&gt;inherit native&lt;br /&gt;&lt;br /&gt;do_configure_prepend() {&lt;br /&gt;    if [ -e ${S}/${TARGET_SYS}-libtool ] ; then&lt;br /&gt;  echo "${TARGET_SYS}-libtool already present"&lt;br /&gt;    else&lt;br /&gt;        cp ${STAGING_BINDIR}/${TARGET_SYS}-libtool ${S}&lt;br /&gt;    fi&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;do_stage () {&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;可能看出 bb 檔在做的事，主要是設定變數以及定義函數 (python or shell script)。Data class 就是用來紀綠 bitbake 從各設定檔跟 bb 檔讀進來各個變數的值。特別值得注意的是，對 Data class 來說，函數跟變數並沒有太大的不同。或者說，函數只是比較特別一點的變數。在上面的例子裡，do_stage() 其實只是定義了一個叫做 do_stage 的變數，而它的值剛好是一段 shell script。bb 檔裡還會出現一些 keyword (require, inherit 等)，parser 在看到它們的時候，不一定是利用 Data class 來紀錄這些資訊。&lt;br /&gt;&lt;br /&gt;在了解 bitbake 怎麼處理變數前我們必須先知道 Data class 提供了哪些機制。我們知道 Data class 是用來紀錄 key-value pairs 用的。又，上面提到有些變數是特殊的，所以每個 key 勢必還要有 flag 來描述其性質 (是不是可以執行，可執行的話是 python or shell script 等)。為了達到這個需求，實作上 Data class 是一個 dict of dict。也就是說，&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;DEPENDS = "gtk-doc-native"&lt;br /&gt;S = "${WORKDIR}/git"&lt;br /&gt;FILES_${PN}-locale = "${datadir}/locale"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;會以&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;d.dict['DEPENDS']['content'] = 'gtk-doc-native'&lt;br /&gt;d.dict['S']['content'] = '${WORKDIR}/git'&lt;br /&gt;d.dict['FILES_${PN}-locale']['content'] = '${datadir}/locale'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;的形式存到 d (an instance of class Data) 裡面。而&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;do_stage () { some_code }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;則會變成&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;d.dict['do_stage']['content'] = 'some_code'&lt;br /&gt;d.dict['do_stage']['func'] = '1'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;利用 dict of dict，Data class 輕易地為任何的 key 提供任意多的性質。&lt;br /&gt;&lt;br /&gt;我們知道了 Data class 讓我們可以為任意的 key 標上任意的性質，但 bitbake 的需求不僅僅只是如此。更重要的是，bitbake 想提供的是變數的處理。從上面的例子可以看到，S = "${WORKDIR}/git" 進到 Data class 裡是 d['S']['content'] = '${WORKDIR}/git' 的形式，WORKDIR 這個變數並沒有被展開。Data class 在變數展開方面採用的是 lazy 的策略。也就是說變數的展開，會在讀值的時候發生。所以要等到稍後某個 task 取 S 的值時&lt;br /&gt;&lt;pre class="programlisting"&gt;cd ${S}&lt;/pre&gt;&lt;br /&gt;WORKDIR 才會被即時展開。&lt;br /&gt;&lt;br /&gt;變數除了可以出現在 value 外也可以出現在 key 的部份 (如 FILES_${PN}-locale)。不同的是，key 的變數展開發生在 d.expandKeys()，而且是不可復原的。它的目的跟我們最後想看的 prepend/append/override 有關。&lt;br /&gt;&lt;br /&gt;在 bb 檔裡頭不難看到&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;do_configure_prepend() { some_code }&lt;br /&gt;do_install_append() { some_other_code }&lt;br /&gt;TARGET_FPU_arm = "soft"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;等語法。這讓開發者可以很輕易地在 task 開始或結束的地方加上一段 script，或者讓開發者可以有條件地設定某個變數。例如，我們可能希望當目標架構是 arm 時把 TARGET_FPU 設成 soft。上面這些語法在 Data class (不完全正確) 的作法是&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;d.dict['do_configure']['_prepend'].append('some_code')&lt;br /&gt;d.dict['do_install']['_append'].append('some_other_code')&lt;br /&gt;d.dict['TARGET_FPU_arm']['content'] = 'soft'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;而 prepend/append/override 發生的時機，不像變數展開是在取值時即時發生，也不像變數展開並不會去修改 d 的值，prepend/append/override 只有在 d.update_data() 時才會發生，而且修改也不可復原。例如當目標架構是 arm 時，TARGET_FPU 會被 override 成 TARGET_FPU_arm 的值&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;d.dict['TARGET_FPU'] = d.dict['TARGET_FPU_arm']&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Override 機制比這邊討論的略為複雜一些。有興趣的人建議可以直接參考實作。&lt;br /&gt;&lt;br /&gt;BitBake parser 規範了 bb 檔的語法。但部份 parser 允許的操作並不被 Data class 直接支援。最後，不妨猜猜看 ?=, :=, += 等操作跟 Data class 如何相互作用？&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-8475741387939745595?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/8475741387939745595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=8475741387939745595' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/8475741387939745595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/8475741387939745595'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2008/12/bitbake-data-class.html' title='一千零一夜之 BitBake Data class'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-5171497720756571226</id><published>2008-12-14T17:09:00.011+08:00</published><updated>2008-12-26T00:48:12.327+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='一千零一夜'/><category scheme='http://www.blogger.com/atom/ns#' term='dri'/><title type='text'>一千零一夜之 DRI</title><content type='html'>&lt;blockquote&gt;這個系列是讀書筆記，作者可能沒有跟主題有關的開發經驗。&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;DRI 讓 X clients 可以直接利用硬體來做繪圖，這點可以利用下面指令看出來：&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;olvaffe@m500:~$ glxgears &amp;&lt;br /&gt;[1] 24684&lt;br /&gt;olvaffe@m500:~$ cat /proc/24684/maps &lt;br /&gt;08048000-0804b000 r-xp 00000000 08:03 80591      /usr/bin/glxgears&lt;br /&gt;0804b000-0804c000 rw-p 00002000 08:03 80591      /usr/bin/glxgears&lt;br /&gt;...&lt;br /&gt;b38fa000-b58fa000 rw-s e6000000 00:0d 7315       /dev/dri/card0&lt;br /&gt;b58fa000-b62fa000 rw-s e5000000 00:0d 7315       /dev/dri/card0&lt;br /&gt;b62fa000-b6cfa000 rw-s e4000000 00:0d 7315       /dev/dri/card0&lt;br /&gt;b6cfa000-b733a000 rw-s 2c200000 00:0d 7315       /dev/dri/card0&lt;br /&gt;b733a000-b797a000 rw-s 2c200000 00:0d 7315       /dev/dri/card0&lt;br /&gt;...&lt;br /&gt;b79a0000-b7bbd000 r-xp 00000000 08:03 347365     /usr/lib/dri/i915_dri.so&lt;br /&gt;b7bbd000-b7bd1000 rw-p 0021c000 08:03 347365     /usr/lib/dri/i915_dri.so&lt;br /&gt;b7c00000-b7c07000 r-xp 00000000 08:03 66335      /usr/lib/libdrm.so.2.3.1&lt;br /&gt;b7c07000-b7c08000 rw-p 00006000 08:03 66335      /usr/lib/libdrm.so.2.3.1&lt;br /&gt;b7eb5000-b7f11000 r-xp 00000000 08:03 69724      /usr/lib/libGL.so.1.2&lt;br /&gt;b7f11000-b7f17000 rw-p 0005b000 08:03 69724      /usr/lib/libGL.so.1.2&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;我們可以看到，glxgears 把 i915_dri.so (intel 的 driver) 載進來並且開啟了 /dev/dri/card0。而在不使用 DRI 的時候：&lt;br /&gt;&lt;pre class="programlisting"&gt;&lt;br /&gt;olvaffe@m500:~$ LIBGL_ALWAYS_INDIRECT=1 glxgears &amp;&lt;br /&gt;[1] 24834&lt;br /&gt;olvaffe@m500:~$ cat /proc/24834/maps &lt;br /&gt;08048000-0804b000 r-xp 00000000 08:03 80591      /usr/bin/glxgears&lt;br /&gt;0804b000-0804c000 rw-p 00002000 08:03 80591      /usr/bin/glxgears&lt;br /&gt;...&lt;br /&gt;b7bd3000-b7bda000 r-xp 00000000 08:03 66335      /usr/lib/libdrm.so.2.3.1&lt;br /&gt;b7bda000-b7bdb000 rw-p 00006000 08:03 66335      /usr/lib/libdrm.so.2.3.1&lt;br /&gt;...&lt;br /&gt;b7e88000-b7ee4000 r-xp 00000000 08:03 69724      /usr/lib/libGL.so.1.2&lt;br /&gt;b7ee4000-b7eea000 rw-p 0005b000 08:03 69724      /usr/lib/libGL.so.1.2&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;則少了上述的檔案。這是因為繪圖方面都轉送給 X server 去處理。如果用 CPU usage 去看，也可以看出在這兩個情形下，比較忙的可能是 server 或著是 client。而就像 client 可以利用 DRI 做加速一樣，X server 在收到 client 的請求時，也可以利用 DRI 去完成這些請求，這個技術被稱為 AIGLX (Accelerated Indirect GLX)。&lt;br /&gt;&lt;br /&gt;從上面的例子我們可以看出 DRI 這個架講的基本組成份子：提供 /dev/dri/card0 的 i915 kernel module、存取這個裝置用到的 libdrm、Mesa 提供的 libGL 與 i915_dri.so、最後 X server 那邊提供了 GLX 跟 DRI server extensions。值得一提的是，X server 這邊雖然沒有用到 libGL，但它其實用到了部份 Mesa 的 source 來實作 GLX 跟 DRI server extensions，在 AIGLX 的情況下，甚至會 dlopen i915_dri.so 來用。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-5171497720756571226?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/5171497720756571226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=5171497720756571226' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/5171497720756571226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/5171497720756571226'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2008/12/dri.html' title='一千零一夜之 DRI'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3519606278200777308.post-3312139792056546865</id><published>2008-01-02T15:05:00.000+08:00</published><updated>2008-01-03T03:02:16.383+08:00</updated><title type='text'>gobject 的 marshaller</title><content type='html'>在剛開始使用 GObject 很容易遇到的一個問題是，marshaller 是什麼？因為在幫自己的物件設計 signal 的時候，有一項資訊就是 marshaller：&lt;br /&gt;&lt;pre class="programlisting"&gt;guint&lt;br /&gt;g_signal_new (const gchar        *signal_name,&lt;br /&gt;            GType               itype,&lt;br /&gt;            GSignalFlags        signal_flags,&lt;br /&gt;            guint               class_offset,&lt;br /&gt;            GSignalAccumulator  accumulator,&lt;br /&gt;            gpointer            accu_data,&lt;br /&gt;            GSignalCMarshaller  c_marshaller,&lt;br /&gt;            GType               return_type,&lt;br /&gt;            guint               n_params,&lt;br /&gt;            ...);&lt;/pre&gt;&lt;br /&gt;雖然說搜尋 glib-genmarshal 可以找到很多生成 c_marshaller 的方法，但我們更感興趣的是為什麼會需要 marshaller 的存在。&lt;br /&gt;&lt;br /&gt;這邊的 marshaller 更精準的說法是 closure marshaller。在 gobject 中，我們利用 g_signal_connect 連接 signal handler 時，所提供的 C 函數會先被包裝成一個 closure，然後這個 closure 才真正地連接上去。上面提到的 c_marshaller 則被用來作為這個 closure 的 closure marshaller。&lt;br /&gt;&lt;br /&gt;Marshaller 自己本身也是 C 函數。在 signal 發生時，gobject 並不會直接呼叫 signal handler，而是呼叫該 handler 對應的 closure marshaller。換句話說，呼叫的動作變成一種間接的行為。&lt;br /&gt;&lt;br /&gt;這層間接提供的好處是，我們的 signal handler 不一定要用 C 來寫。只要提供適當的 closure marshaller，signal handler 可以用任何語言來寫。當然這時就得用比 g_signal_connect 提供更大彈性的&lt;br /&gt;&lt;pre class="programlisting"&gt;gulong&lt;br /&gt;g_signal_connect_closure (gpointer     instance,&lt;br /&gt;                          const gchar *detailed_signal,&lt;br /&gt;                          GClosure    *closure,&lt;br /&gt;                          gboolean     after);&lt;/pre&gt;&lt;br /&gt;來連接 signal handler。&lt;br /&gt;&lt;br /&gt;gobject 的各種 bindings 就可以充份利用 gobject 的這項機制。像是 Perl binding 即提供了 gperl_closure_marshal 來當 marshaller，溝通在 Perl 與 C 之間。&lt;br /&gt;&lt;br /&gt;Closure 是 gobject 用來一般化 callback function 的方法。伴隨著 callback function，資料也會在不同的語言中交換。對於資料，gobject 是用 GValue 來處理交換的問題。雖然用了不同的名詞，但G_VALUE_LCOPY 跟 G_VALUE_COLLECT 實際上就是 GValue 給 C 通用的 marshaller 跟 demarshaller。&lt;br /&gt;&lt;br /&gt;要更清楚了解 marshaller/demarshaller 的意義，除了各 bindings 外，也可以參考 dbus-glib 的實作。在裡頭，可以看到 dbus message arguments 怎麼被 demarshal 成 GValue's 再被 marshal 成 C 型別；或者是相反過來的程序。dbus-glib 為了效能考量，有做了一些壞事。這些壞事反而是了解 gobject 很好的參考。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3519606278200777308-3312139792056546865?l=olvaffe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://olvaffe.blogspot.com/feeds/3312139792056546865/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3519606278200777308&amp;postID=3312139792056546865' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/3312139792056546865'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3519606278200777308/posts/default/3312139792056546865'/><link rel='alternate' type='text/html' href='http://olvaffe.blogspot.com/2008/01/gobject-marshaller.html' title='gobject 的 marshaller'/><author><name>olv</name><uri>http://www.blogger.com/profile/14109154724494271204</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/_e4cXiDy19_c/SxzlLF9y7JI/AAAAAAAAAfY/Do83VK8EWuw/S220/img_1133.jpg'/></author><thr:total>0</thr:total></entry></feed>
