Skip to content

Instantly share code, notes, and snippets.

@poutyface
Created September 17, 2011 02:25
Show Gist options
  • Save poutyface/1223553 to your computer and use it in GitHub Desktop.
Save poutyface/1223553 to your computer and use it in GitHub Desktop.
QEMU: 仮想ボード ARM Cortex-A9 マルチコアで Linux を動かす
モチベーション
---------------
Androidのエミュレータは中でQEMUを使ってる
中で使われているので、Android開発とは直接関係がないけど、
素のQEMUの使い方を知る。
* QEMUの使い方を覚える
* Linuxをエミュレータ環境で動かしてみる
* ARM のクロス環境に慣れてみる
* ARM はマルチコア
環境
-----
Linux 2.6.38-11-generic Ubuntu SMP
kernel-v2.6.39
QEMU emulator version 0.14.0 (qemu-kvm-0.14.0)
linux kernelをコンパイル
-------------------------
$ cd kernel-v2.6.39
$ export ARCH=arm
$ export CROSS_COMPILE=arm-none-linux-gnueabi-
クロス環境のツールチェインはCodeSourceryのツールチェインを使用する
https://sourcery.mentor.com/sgpp/lite/arm/portal/subscription?@template=lite
target OS GNU/LinuxをダウンロードしてbinにPATHを通す.
$ make realview_smp-defconfig
ターゲット向けのコンフィグレーションファイルを作る。
あらかじめ用意されているコンフィグレーションがあるので(XXX-defconfig)を
それを指定する. 今回はSMPなので realview_smp-defconfigを指定.
ターゲットのコンフィグレーションファイルの種類はARMの場合,arch/arm/configsで確認できる。
$ make menuconfig
 ARMv7アーキテクチャに設定する、またCortex-A9を使用する.
 
* loadable module support [disabled]
* Platform Baseboard for ARM11 [disabled]
* Support ARM ARMv6 [disabled]
* PBX A9 and ARMv7 [enabled]
-> Support RealView(R) Emulation Baseboard
-> Support Multicore Cortex-A9 Tile
* Support RealView(R) Platform Baseboard Explore [enabled]
* CONFIG_REALVIEW_HIGHT_PHYS_OFFSET [disabled]
RealView platform type
-> Hight physical base address for the RealView platform
* EABI(allowing also old ABI) SupportがEnabledになっているかを確認すること
これはCodeSourcery toolchainでコンパイルするので必要
** Network device support
-> Network Ethernet (10 or 100Mbit)
->SMSC LAN911X [disabled]
  qemu-0.14.0でハードフェアエラーがでるためdisabledにする
  
  
ビルドが成功するとarch/arm/boot/zImageにカーネルイメージが出来上がる
このカーネルイメージはQemuで実行することができる
Kernel の起動を確認する
------------------------
シングルコアでの起動を確認
qemu-system-arm -M realview-pbx-a9 -m 128M -kernel kernel-v2.6.39/arch/arm/boot/zImage -nographic -append "console=ttyAMA0 mem=128M"
マルチコアでの起動を確認
qemu-system-arm -M realview-pbx-a9 -m 128M -kernel kernel-v2.6.39/arch/arm/boot/zImage -nographic -smp 2 -append "console=ttyAMA0 mem=128M"
initrd(ルートファイルシステム)を指定していないので、途中でエラーになるのが正しい
-M : 仮想ボードのモデル名
-m : メモリ容量
-kernel : linux kernelのイメージ
-nographic : windowでなくconsoleで
-append : カーネル起動パラメータを指定する
-smp : CPUコアの数
Note:
モデル名は qemu-system-arm -M ? でリストが表示される
QEMUを抜けるには Ctrl-A, x を順番にタイプする。
確認用のinitrdの作成
---------------------
確認のためにinitrdを作成し、正しく起動するかを確認してみる
普通のlinuxであると、ルートファイルシステムはさまざまなディレクトリ(/bin, /etc, /usr等) がある
が、これは後回しで、簡単なプログラムを1つ作成して、1ファイルを含むだけのinitrdを作ってみる.
-- test.c
#include <stdio.h>
void main()
{
printf("Welcome world\n");
while(1);
}
----
 Note:
  while(1) でループしているのは、linuxがこのプログラムを初めに動かすので、プログラムを
  終了させないため
$ arm-none-linux-gnueabi-gcc -static test.c -o test
$ echo test | cpio -o --format=newc > rootfs
$ qemu-system-arm -M realview-pbx-a9 -m 128M -kernel kernel-v2.6.39/arch/arm/boot/zImage -nographic -initrd rootfs -smp 2 -append "root=/dev/ram rdinit=/test console=ttyAMA0 mem=128M"
Note:
cpioはfilesystemを作るのに使われる。cpioはファイルのリストを入力しアーカイブを出力する。
formatにnewcを指定するとinitramfs形式のフォーマット。
いま作成したrootfsはtestバイナリファイルを1つ含んだファイルシステムイメージで、これを
QEMUのinitrdパラメータに渡すことができる。
-initrd でinitrd を指定する
-append でrdinit=に初めに実行するプログラムを指定できる
上手く動いていれば "Welcom world" が最後に出力される。
BusyBoxを使用してツールを作成する, initrdも作成
------------------------------------------------
上記でlinuxは起動できたが、いろいろツールが足りないので、BusyBoxでターゲット用の
各種ツール群を作成する。
BusyBoxはコンパクトなファイルシステムを必要とする組み込みlinuxでよくつかわれる、
さまざまなシステムユーティリティを提供する。
busybox-1.19.2
http://www.busybox.net/
$ export ARCH=arm
$ export CROSS_COMPILE=arm-none-linux-gnueabi-
$ make defconfig
$ make menuconfig
デフォルトのコンフィグレーションではかなりの数のツールが選択されているので、ほしいものだけ
をチェックする。コンパイル途中でエラーがでたら素直に外すのが吉
$ make install
ビルドが成功すると _install/ にルートファイルシステムのツリーが生成される。
これらを前回の"Welcome world"と同じように、cpioツールを使用してlinuxのルートファイル
システムイメージを作ると出来上がり。
$ cd _install
$ find . | cpio -o --format=newc > ../rootfs.img
$ cd ..
$ gzip -c rootfs.img > rootfs.img.gz
$ qemu-system-arm -M realview-pbx-a9 -m 128M -kernel kernel-v2.6.39/arch/arm/boot/zImage -nographic -initrd rootfs.img.gz -smp 2 -append "root=/dev/ram rdinit=/bin/sh console=ttyAMA0 mem=128M"
rdinit=で/bin/shを指定しているのでシェルが立ち上がる。ls, pwd等のコマンドが使えるようになっている。
一方今のままでは、psコマンドが使えない。これは特殊なファイルシステムが/procが必要なので作成する必要がある。
$ mkdir /proc
$ mount -t proc none /proc
また、/devがconsoleデバイスを除いて、空っぽである。こちらも特殊なファイルシステム/sysを作成する
$ mkdir /sys
$ mount -t sysfs none /sys
$ mdev -s
これらのマウント処理は通常、起動時に/sbin/initにさせることができる。
/sbin/initは通常linux kernelによって最初に起動されるプログラムである。
initに何かをさせるには/etc/init.d/rcSに記述する。
なのでBusyBoxで_installを作成したあとに各種設定ファイルを追加して、cpio -> gzip でinitrdを作れば
いいだろう
$ cd _install
$ mkdir proc sys dev etc etc/init.d
$ cd ..
-- _install/etc/init.d/rcS
#!/bin/sh
mount -t proc none /porc
mount -t sysfs none /sys
/sbin/mdev -s
---
$ chmod +x _install/etc/init.d/rcS
この内容で、またrootfs.img.gzを作成
今回は、rdinit=/sbin/initを指定する
$ qemu-system-arm -M realview-pbx-a9 -m 128M -kernel kernel-v2.6.39/arch/arm/boot/zImage -nographic -initrd rootfs.img.gz -smp 2 -append "root=/dev/ram rdinit=/sbin/init Console=ttyAMA0 mem=128M"
appendix
---------
QEMUでは-kernelオプションに渡されたバイナリファイルを0x00010000にロードする。
エミュレータは0x00000000番地からスタートするが、ここには予めいくつかのインストラクションが
含まれており、最終的に0x00010000にジャンプするようになっている。このことから
あるプログラムをQEMU上で単に実行するには、0x00010000でリンクされたバイナリを作成することで
実行できる
startup.o
------------
.global _Reset
_Reset:
LDR sp, =stack_top
BR c_entry
B .
test.ld
--------
ENTRY(_Reset)
SECTIONS
{
. = 0x10000;
.startup . : { startup.o(.text) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
. = . + 0x1000;
stack_top = .;
}
-----
$ arm-none-eabi-as -mcpu=arm926ej-s -g startup.s -o startup.o
$ arm-none-eabi-gcc -c -mcpu=arm926ej-s -g test.c -o test.o
$ arm-none-eabi-ld -T test.ld test.o startup.o -o test.elf
$ arm-none-eabi-objcopy -O binary test.elf test.bin
-----
arch/arm/mach-<mach>/Makefile.boot
zreladdr: head.SがRAMにzImageを展開したあとのKernelのスタートアドレス
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment