2009年4月7日火曜日

kernel 2.6.29 と差し替えてみる

QEMU のサイトからダウンロードできる arm-test 0.2 の kernel を差し替えてみる。

http://www.nongnu.org/qemu/arm-test-0.2.tar.gz

kernel.org から最新の 2.6.29 を取ってくる。

http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.29.tar.bz2

クロスコンパイラは、結局 CodeSourcery から持ってきた。

http://www.codesourcery.com/sgpp/lite/arm/portal/subscription?@template=lite

VMWare 上に最低限の Debian 5.0.0 環境を作ってインストール (単に tarball を展開するだけでも OK)。
.bashrc に

export LANG=C
export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabi-
export PATH=/path/to/CodeSourcery/Sourcery_G++_Lite/bin:$PATH

ARCH が大文字じゃないと駄目なので注意(参考サイト [1] では小文字になっててはまった…)。

参考サイト

[1] http://fedoraproject.org/wiki/Architectures/ARM/HowToQemu
[2] http://d.hatena.ne.jp/himainu/20080430


$ cp arch/arm/configs/versatile_defconfig .config
$ make menuconfig

Enable DHCP Support (CONFIG_IP_PNP_DHCP).

Networking -> Networking Support -> Networking Options -> TCP/IP Networking ->

Enable Universal Tun/Tap Driver Support (CONFIG_TUN)

Device Drivers -> Network Device Support ->

Enable ARM EABI Support (CONFIG_AEABI)

Kernel Features ->

Enable tmpfs support (CONFIG_TMPFS)
File Systems -> Pseudo File Systems ->

Enable PCI (CONFIG_PCI)

SCSI LOW level drivers -> CONFIG_SCSI_SYM53C8XX_2

$ make

できた arch/arm/boot/zImage を持ってきて、arm-test 以下に置いたと仮定して。

$ qemu-0.9.1/arm-softmmu/qemu-system-arm.exe -M versatilepb -kernel arm-test/zImage -initrd arm-test/arm_root.img

で起動した。ちょっとフォントが変だけど…

2009年4月3日金曜日

machine number

Linux Kernel は、ブートローダの中でマシンチェックを行っているので、r1 レジスタに適切な machine number を入れておかないとブートできない。

http://www.arm.linux.org.uk/developer/machines/

を見ると ARM Versatile Porting Board (versatile_pb) は 387 と書いてある。

QEMU の hw/versatilepb.c を見ると、vab_init() の中で versatile_init() の最後の引数に 0x183 を指定して呼び出している。まさしく 0x183 = 387。

というわけで、マジックナンバーの謎が解けた。linux kernel のロードのための引数だったのね。static

void vpb_init(int ram_size, int vga_ram_size,
const char *boot_device, DisplayState *ds,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename, const char *cpu_model)
{
versatile_init(ram_size, vga_ram_size,
boot_device, ds,
kernel_filename, kernel_cmdline,
initrd_filename, cpu_model, 0x183);
}

...

QEMUMachine versatilepb_machine = {
"versatilepb",
"ARM Versatile/PB (ARM926EJ-S)",
vpb_init,
};

2009年2月7日土曜日

QEMU stdvga

http://hrb.osask.jp/wiki/?advance/QEMUVGA

vl.c の中でオプション解析。デフォルトは cirrus_vga_enable になってるみたい。

pci/isa_vga_init() で作ったビデオカードが stdvga 相当になるみたい。
(他はそれぞれ、vga の代わりに cirrus  や vmsvga が付いた初期化関数を使う)

2009年2月5日木曜日

QEMU base emulator

Bishop エミュレータ

やはりこの会社は、Android もやってるみたい。

2009年1月30日金曜日

parent_irq

QEMU の仮想デバイス (例えば i8259) には、parent_irq というメンバーが存在することが多い。

これにより、複数のデバイスの IRQ を繋げることができるようだ。なるほど、よくできてる。

大抵は、初期化の時に cpuirq などの、CPU と直結する IRQ (ハンドラの中で cpu_interrupt() を呼ぶ) を作っておいて、これをトップレベルの parent_irq とする。

2009年1月24日土曜日

ldl_code の続き

grep しても見つからないわけだ。disas_arm_insn 内の ldl_code の正体は、例のこれ。
#define ACCESS_TYPE (NB_MMU_MODES + 1)
#define MEMSUFFIX _code
#define env cpu_single_env

#define DATA_SIZE 1
#include "softmmu_header.h"

#define DATA_SIZE 2
#include "softmmu_header.h"

#define DATA_SIZE 4
#include "softmmu_header.h"

#define DATA_SIZE 8
#include "softmmu_header.h"

#undef ACCESS_TYPE
#undef MEMSUFFIX
#undef env

#endif
これで、softmmu_header.h 内の
/* generic load/store macros */

static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
{
    int index;
    RES_TYPE res;
    target_ulong addr;
    unsigned long physaddr;
    int mmu_idx;

    addr = ptr;
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
    mmu_idx = CPU_MMU_INDEX;
    if (__builtin_expect(env->tlb_table[mmu_idx][index].ADDR_READ !=
                         (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
        res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx);
    } else {
        physaddr = addr + env->tlb_table[mmu_idx][index].addend;
        res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
    }
    return res;
}
これが tatic inline uint32_t  ldl_code(target_ulong ptr) に特殊化される。
/* generic load/store macros */

static inline uint32_t ldl_code(target_ulong ptr)
{
    int index;
    uint32_t res;
    target_ulong addr;
    unsigned long physaddr;
    int mmu_idx;

    addr = ptr;
    index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
    mmu_idx = CPU_MMU_INDEX;
    if (__builtin_expect(env->tlb_table[mmu_idx][index].ADDR_READ !=
                         (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
        res = __ldl_cmmu(addr, mmu_idx);
    } else {
        physaddr = addr + env->tlb_table[mmu_idx][index].addend;
        res = ldl_raw((uint8_t *)physaddr);
    }
    return res;
}
考えてみれば当たり前。全ての (QEMU 上の仮想 RAM への) メモリアクセスは (QEMU の仮想) MMU 経由で行わないといけないのだから。

2009年1月23日金曜日

disas_arm_insn

target-arm/translate.c の
static void disas_arm_insn(CPUState * env, DisasContext *s)
{
    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;

    insn = ldl_code(s->pc);
ここで s->pc は、ロードされたターゲットのマシン語の pc だ。

cpu-all.h を見ると。
#define ldl_code(p) ldl_raw(p)
#define ldl_raw(p) ldl_p(laddr((p)))
#define laddr(x) (uint8_t *)(long)(x)
#define ldl_p(p) ldl_le_p(p)  /* !defined(TARGET_WORDS_BIGENDIAN)  */
static inline int ldl_le_p(void *ptr)
{
    return *(uint32_t *)ptr;
}
う~ん、なぜこれで命令が取ってこれるのかよくわからない。
メモリのどこに、ターゲットの命令はロードされてるんだ ?
たぶん phys_ram_base とかだと思っていたんだけど、違うのかな ?

追記

これは CONFIG_USER_ONLY 版のコードなので、全く関係無かった。

しかし、どこに定義があるんだ… grep した限りでは見つけられなかった。