2014年5月27日 星期二

使用 GDB 連上 ARM64 QEMU 進行kernel level的單步執行

先留一下筆記。

前篇文章已經可以把ARM64的kernel與rootfs編譯好,並且在QEMU跑起來。所以嘗試使用gdb對QEMU做kernel level的單步執行。

1) 將 qemu 跑起來,並等待 gdb 來連接 (多了參數-s -S)

    $ ./qemu.git/aarch64-softmmu/qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -nographic -smp 1 -m 2048 -kernel ../kernel/arch/arm64/boot/Image  --append "console=ttyAMA0" -s -S

2) 將gdb跑起來並連接到 QEMU

    $ aarch64-linux-gnu-gdb

(gdb) file vmlinux         ---> 載入kernel的binary
Reading symbols from /home/jesse/studies/arm64/linux.git/vmlinux...done.
(gdb) directory /home/jesse/studies/arm64/linux.git/   ---> 告知source code目錄
Source directories searched: /home/jesse/studies/arm64/linux.git:$cdir:$cwd
(gdb) target remote 10.10.10.10:1234       ---> 連上QEMU
Remote debugging using 10.10.10.10:1234
0x0000000040000000 in ?? ()
(gdb) break start_kernel              ---> 設break point
Breakpoint 2 at 0xffffffc0005c94a0: file init/main.c, line 480.
(gdb) c                          ---> 讓kernel開始繼續執行
Continuing.

Breakpoint 2, start_kernel () at init/main.c:480             ---> 遇到中斷點,kernel停下來
480 {
(gdb) list                  ---> 看一下現在source code
475 pgtable_init();
476 vmalloc_init();
477 }
478
479 asmlinkage __visible void __init start_kernel(void)
480 {
481 char * command_line;
482 extern const struct kernel_param __start___param[], __stop___param[];
483
484 /*
(gdb) step             ---> 單步執行
489 smp_setup_processor_id();

2014年5月26日 星期一

ARM64 研究

ARM64如火如荼的進行著,從原本的ARM 32bit跨入到新的AArch32/64究竟有多少改變?好像已經沒辦法像之前透過簡單study就通盤了解。為了保持老老工程師的競爭力,只好確實擬訂讀書計畫,期待能夠窺探ARM 64bit的世代的改變。

首先,計畫才一開始,甚麼頭緒也沒有。所以我們先嘗試著建置學習環境,建置過程中再慢慢思考需要研究哪些topic幫助了解64bit的世界。

參考了幾個網站之後,主要是 http://www.bennee.com/~alex/blog/2014/05/09/running-linux-in-qemus-aarch64-system-emulation-mode/

建置環境的步驟如下:

0. 準備toolchain

  $ wget http://releases.linaro.org/12.10/components/toolchain/gcc-linaro/aarch64/rc3/gcc-linaro-aarch64-linux-gnu-4.7+bzr115029-20121015+bzr2506_linux.tar.bz2
$ tar xf gcc-linaro-aarch64-linux-gnu-4.7+bzr115029-20121015+bzr2506_linux.tar.bz2
$ export PATH=$PATH:$PWD/gcc-linaro-aarch64-linux-gnu-4.7+bzr115029-20121015+bzr2506_linux/bin

1. 取得kernel source。

    $ git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

2. Setup ARM64 QEMU. (以QEMU做為我們硬體的環境)

  $ git clone git://git.qemu.org/qemu.git qemu.git
  $ cd qemu.git
  $ ./configure --target-list=aarch64-softmmu
  $ make

3. Build your own rootfs

  $ git clone git://git.buildroot.net/buildroot buildroot.git
  $ cd buildroot.git
  $ make menuconfig

  Configure it

  * Target Options -> Target Architecture(AArch64)
  * Toolchain -> Toolchain type (External toolchain)
  * Toolchain -> Toolchain (Linaro AArch64 14.02)
  * System configuration -> Run a getty (login prompt) after boot      

    (BR2_TARGET_GENERIC_GETTY)
  * System configuration -> getty options -> TTY Port (ttyAMA0) 
    (BR2_TARGET_GENERIC_GETTY_PORT)
  * Target Packages -> Show packages that are also provided by busybox 
    (BR2_PACKAGE_BUSYBOX_SHOW_OTHERS)
  * Filesystem images -> cpio the root filesystem (for use as an initial RAM 
    filesystem) (BR2_TARGET_ROOTFS_CPIO)
    $ make

4. Build Kernel and Run it on QEMU.


  Configure Kernel

  * CONFIG_CROSS_COMPILE="aarch64-linux-gnu-"                                               # needs to match your cross-compiler prefix
  * CONFIG_INITRAMFS_SOURCE=
    "/home/alex/lsrc/qemu/buildroot.git/output/images/rootfs.cpio"  
    # points at your buildroot image
  * CONFIG_NET_9P=y                                                                         # needed for virtfs mount
  * CONFIG_NET_9P_VIRTIO=y

  $ ARCH=arm64 make -j 8

5. Run your kernel and rootfs on ARM64 QEMU

    $ ./aarch64-softmmu/qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -nographic -smp 1 -m 2048 -kernel ../linux.git/arch/arm64/boot/Image  --append "console=ttyAMA0"
    

以上,應該可以跑起來。下個階段嘗試使用GDB進入,以便進行kernel source level的單步執行。

2013年8月25日 星期日

LLVM

LLVM 是一個大約在2000年的專案。由於這個專案和幾個前輩爭取的一個專案雷同,所以多年來一直有在關注他們的發展動態。當初前輩的案子因為沒獲得評審青睞,沒爭取到經費運作。

事隔審核失敗的一兩年,無意中發現到LLVM專案出現的時候,覺得很興奮。十多年下來,一方面好奇他們究竟會走到甚麼程度,另外一方面也會想想當初要是審核過關了,能不能做出相同的成就。當然,免不了也會酸一酸當初這些評審沒眼光。

LLVM起初是設計一個低階的virtual machine,包含許多編譯與除錯工具,但是隨著應用越來越多,LLVM得到更多的關注。LLVM如今搖身一變為整個專案的代名詞,不再只侷限於字詞上『Virtual Machine』的意義。

更由於它的BSD授權,在GCC宣布進入GPLv3時代之後,廠商更寄望能由它從GPLv3的限制中解套。現在不僅Mac OS, FreeBSD拿去當成取代GCC的工具,還有像是GPGPU方面的應用,Android和GLSL拿它來當成code gen的backend。

1. 維基
2. LLVM網址

不知道LLVM會走到甚麼地步,但是它的彈性也為跨平台平行處理帶來一些可能性。

2013年8月23日 星期五

Memory Management Article

web version: https://www.kernel.org/doc/gorman/html/understand/index.html pdf version: http://ptgmedia.pearsoncmg.com/images/0131453483/downloads/gorman_book.pdf 工作的關係,好久沒有更新網誌。最近因為新專案找到一個舊資料,對memory management了解還 蠻有幫助的。雖然是舊資料,對許多觀念卻有相當深入的解釋,有心想朝Linux Kernel發展的人, 應該還蠻值得讀。有些細節還沒消化完,有空再寫分享。

2009年12月20日 星期日

Trace Linux Kernel的一些想法~

之前貼了一些自己 trace linux kernel 的一些筆記文,筆記
式的文章難免寫得比較瑣碎,閱讀起來應該比較不容易,尤其逐
行trace,應該會有人很排斥或是不認同這樣的一種方式,之前
曾經看到一些文章甚至會明白地提醒讀者切記不要逐行研究程式
碼,要將其觀念記住才是重點。

這邊想針對這樣的論點提一些想法給大家參考,目的不是要訂出
一個好與壞,其實我覺得兩種方法並不相衝突,而是大家在學習
的階段,可以依照理解程度來做取捨。

以自己的經驗來說,以前一開始囫圇吞棗,試圖去理解書上提到
的觀念,似懂非懂的記了許多東西,但是往往人家問我:
『你能夠自己寫出一個OS或是其中一部分功能嗎?』
似乎就變得很心虛,只能告訴對方『我知道它的實作原理』,但
是說要自己要寫,好像就是少了點什麼? 好像懂,但是要怎麼真
正的寫出來,卻是不怎麼敢肯定。

面對這樣的狀況持續一段時間,讓人真正有自信能夠依樣畫葫蘆
弄出個什麼東西,卻是在花心思從很基本的instruction set
開始K和逐行逐行了解之後,才覺得似乎概念和實作有了那麼一
點連接。也由於這樣的基礎,有時候有助於資料不足的狀況下,
還能夠經由看程式碼來補足資料不足的部份,甚至可以用來印
證自己的想法。

這樣的說起來多看程式的好處多多囉?

好像也不盡然,自己的經驗是,看上老半天,一大段雖然每個字
都看得懂,但是兜起來就是不曉得他要做啥用? (看英文的時候
....恩...好像也是這樣 )有時回頭翻書,看看觀念,才會發
現這一段天書似的程式碼所隱含的意義,自然就理解了。

所以後來想想要深入kernel source的方式,似乎得要雙管齊
下,一邊看觀念,一邊找出相對應的程式碼出來,最後觀念與觀
念之間,必定有一些很細節的部份沒有被提到,玩家就得自己想
辦法將他們串起來,一旦書本上的觀念可以在實際程式上得到印
證,那這樣改天要改寫,也就遊刃有餘。

這邊想特別提到的還是閱讀指令集的重要性,對指令的熟悉,不
但對閱讀低階的程式碼有很大的幫助,還對於整個系統演進了解
更為透徹。以前會覺得了解太低階的東西用處不大,後來才覺得
這些部分有時卻影響很大。

以上無聊閒談,歡迎大家提出自己的經驗,交流一下~

2009年12月11日 星期五

Platform Driver~

當我們在重新規劃新的system or hardware platform的時候
常用的作法是拿原廠的reference design當參考
上頭component常常會換掉
舊的平台和新的平台之間
常常某些部份只是位址的更動
例如:本來GPU的base address是0x80001000換到0x80002000
hardware的功能和行為是一樣的

面對的這樣的問題,在舊一點的Linux Kernel我們通常可以用
1) dynamical insert module 的方式將新的 base address 傳給 driver
或者
2) 更改 driver 的 code 直接使用新的 0x80002000 的 base address

在新一點的Linux的kernel導入的所謂的platform driver的概念
概念上我們將某一些和platform相關的資訊放在platform的level (arch/arm/mach-xxx/)
原本的driver放在./drivers/
這樣一來只要選擇到對的platform,相對應的資訊就會pass給driver
如此一來對developer來講就變得比較直覺
driver本身只要針對不同的設定去動作
不需要因為平台改變了
就改寫driver

這樣的機制對於生產SoC的vendor相當便利
因為不同的SoC經常需要對base address做調整
不同的SoC只要從platform level傳遞變更的資訊給driver
新的平台就可以得到driver的支援
而對下游的廠商來說
他們編譯新的kernel時,只要選擇對的platform
就可以得到對的結果

由以上的介紹
我們可以得知platform driver需要透過兩個部分的支援
1) platform level - 提供硬體平台資訊,例如irq line, base address, etc。
2) driver level - 控制硬體平台和實現功能。

首先,概念上我們必須對系統註冊一個新的platform device,使用的方式就是呼叫
platform_device_register( information ); 將所有platform用到的device和相關的資
訊註冊。

接著drvier level這邊,我們會使用 platform_driver_register()將driver註冊到系統
裡頭,假如有任何platform device指定了這個driver,就可以將driver初始化,請它
來服務這個device。

明眼人應該不難發現
新的機制將hardware information和功能實作的分開了
資訊放到platform level規劃
將driver功能實作獨立出來
(其實有點像是C++導入了template的概念,將資料型別和演算法分開)

2009年12月7日 星期一

Cache, Write Buffer 與Device效能~

在很早以前的CPU是很單純的,固定從某一個地方去讀取下一道指令,照著指令要它做什麼就做什麼,隨著電子電路的進步,CPU和周邊的速度出現了極大的差距,CPU常常需要花時間在等待資料讀取或是寫入的動作而不是執行真正的運算工作,因此新的CPU架構:

1) 在CPU和存取的實際位址之間加入了Cache的機制
2) 在資料寫入的過程中加入 Write Buffer 來平衡兩邊的速度差異

Cache的好處是讓CPU可以有一個快速的記憶體減少等待的時間,缺點就是這塊叫做Cache的記憶體比較小,無法容納整個RAM裡頭的資料。而Write Buffer則是用來緩衝Cache和RAM之間的速度差異,而且在較新的CPU當中,還可以設定write-combine的屬性,讓連續位址存取,可以只透過一次的讀寫就達成,大大增加效率。

只是以上這些,究竟對一個撰寫device driver的工程師有什麼好處,因為提到CPU變快變好,好像只會讓一般軟體變快,driver應該不需要特別修改,也不會比較快速。

其實這幾項變革,對撰寫driver來說是有需要特別注意的小地方,而且對某些種類的driver大大有益處。

首先是Cache,CPU會把要寫入的資料先寫在Cache,而不是直接到要寫的位址上,這樣CPU等待時間很少,可是實際上要寫driver的時候,可能因為是要對device上的控制暫存器作讀寫,卻變成被cache住,動作沒有真正及時的被執行,造成程式人員以為已經寫入,實際上是寫到cache裡頭去了。因此,撰寫driver的時候首先要注意某些存取區段需要用non-cache的屬性。若是非得要用cache,那device就得考慮到cache和device/RAM的資料同步的問題。

再來是write-combine的屬性,利用現在記憶體的特性,將連續位址存取的命令合成一次,這對處理multimedia data的hardware相當有用,效能可以提升30%以上。

以上簡單的介紹對一些撰寫driver時,因為CPU不同特性造成device driver需要修改或是效能不同的現象和簡單原理,其他其實還有像是某些連接bus的device(像是pci/agp/pcie),其實也有一些需要注意的地方,了解來龍去脈,寫出來的driver才會大大加快。

搜尋此網誌