Arm Embedded System Labs With Qemu

These labs are based on an ARM simulator(QEMU) in linux environment. The content includes building a linux kernel and root file system, generating the toolchain, cross debugging using cross-gdb, and simple ISR design.


Use buildroot(it can also create file system, but in my lab, I only used it to create toolchain). Before compiling the toolchain's codes, I setup configuration by "make menuconfig". In config file, deselect build kernel, build file system, and enable NFS. The toolchain I created includes tools such as arm-linux-uclibc-gcc, arm-linux-uclibc-ldd


I downloaded kernel source code from linux official website, and used an open source configuration file to setup the configuration of the kernel. This configuration will setup a small kernel(using ramdisk) which is suitable for ARM system. Used cross-compiler arm-linux-uclibc-gcc to compile it.
For different hardware architecture, we might need to do some modification on kernel source (such as adjusting memory mapped IO address…). We can use corresponding patch file to achieve this required modification.

Root File System

Root file system is the smallest set of files and directories that required by the operating system. It includes initrd, init.d, /etc, /proc, /lib, tools such as ls, mount, and so on. I used busybox to create the root filesystem executable file, and used an open source configuration file to setup the configuration. After generating the root filesystem, I need to manually create some necessary files and directories, such as /etc, init.d, /dev, /root, /tmp, and some scripts file.
I used NFS (put root file system's files into a NFS directory) between the host and target, without really write the root file system in target board.
Question: Why we can use NFS without RFS installed.

Debug using Cross-GDB

若要進行遠端除錯,我們需要編譯在 target 端執行的 gdbserver (add in the root file system for target) 以及在 host 端控制 gdbserver 的 gdb ,因為 gdbserver 的程式較原來的 gdb 簡單,因此通常 gdbserver 會比 gdb 本身還要容易 port 到 target 上去,但是在使用上又和原本的 gdb 相同。把target用的gdb server放在NFS directory裡就可以了。


1) 在 target 端用 gdbserver 開啟要除錯的程式,並監聽某一個 port ,等待 host 端的 gdb 連線進來。

進行此步驟前,請先用 QEMU 載入 linux kernel ,並切換到 gdbserver 和 bug 所在的目錄,就可以鍵入

./gdbserver bug

Note 是 host 端的 IP
5566 是 gdbserver 監聽的 port
bug 是要偵錯的程式

2) 從 host 端連到 target 進行 debug

在 host 端也用 gdb 執行同一個程式,在此還需要引入程式的理由是因為 gdbserver 只負責控制程式,但關於程式碼的內容等和程式執行本身的資訊還是由 gdb 自己負責。

首先,先用 gdb 引入 bug

arm-linux-uclibc-gdb bug

接著,連線到 target 端

target remote
即可進行 debug 。

Note 是 target 端的 IP

Interrupt & Exception


In this lab, I observe and modify the source code of SD card device driver. In the code, it registers an IRQ by ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);, where mmci_irq is a function which is also defined in the code as ISR for the interrupt "dev->irq[0]".
I add a line printk("\n-----\nInvoke mmci_irq()\n-----\n"); in mmci_irq(), and recompile the kernel. After that, I can see the message when the interrupt for SD card device driver is triggered.


1. 定義新的system call c source file. ex. mysyscall.c
2. 註冊 system call 的名字
3. 定義新 system call 的代碼
4. 調整 Makefile,使 systam call 被包含在 kernel 中
5. 增加 system call 的 header file,讓 user program 能夠 include且呼叫system call
之後只要在user program裡include header file, 就可以使用system call了

Timer Interrupt

  • The initialization process for system timer is defined in the function time_init() in <linux>/arm/kernel/time.c. I use printk to print a message in this function.
  • The timer interrupt frequency is defined in <linux>/include/linux/jiffies.h by #define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8)). I modify it to be CLOCK_TICK_RATE/10, so the interrupt frequency increase to 10 times.
  • After interrupt frequency is increased to 10 times, I executed a function to analyze the performance. The performance with 10 times interrupt frequency is much worse. That is because the interrupt frequency is too high, and CPU spends too much time on context switching, so introduce much overhead.
  • The system timer ISR is defined in <linux>/kernel/timer.c. System timer ISR includes top half and bottom half, CPU will execute top half first, and then execute bottom half when CPU is free.

Device Driver

  • Device driver is a part of kernel, it is used to support communication between peripheral devices(or virtual devices which are mounted onto kernel) and user program.
  • Device drivers can be classified to block device driver and character device driver. The former transmit fixed number of bytes of data, and the latter transmit variable number of bytes of data.
  • In Linux, we can designed a device as a module, which can then be mounted on kernel. To do that, we need to define several function: module_init(), module_exit(), read(), write(), iotcl(), open(), and release().
  • After that, we need to register the device by "mknod /dev/demo c 60 0", then we can load the device by insmod, release it by rmmod, check it by lsmod, and access it by fread(), fwrite(), fopen(), fclose().

Reference — OpenCSL

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License