U-Boot (aarch64) on Qemu を動作させたい (6)
現在は、仕事で触れている freescale の ls1046a Reference Design Board の U-Boot を Qemu で動作させるべく、仮想ボードを作成中。
CPU, RAM, UART と何とか整えてきて、i2c の調整を行っています。
U-Boot 2016.092.0+ga06b20925c (Oct 22 2017 - 21:04:46 +0900) SoC: LS1046AE Rev1.0 (0x87070010) Clock Configuration: CPU0( ):800 MHz CPU1( ):800 MHz CPU2( ):800 MHz CPU3( ):800 MHz Bus: 600 MHz DDR: 2100 MT/s FMAN: 800 MHz Reset Configuration Word (RCW): 00000000: 0c150010 0e000000 00000000 00000000 00000010: 11335559 40000012 60040000 c1000000 00000020: 00000000 00000000 00000000 00238800 00000030: 20124000 00003000 00000096 00000001 Model: LS1046A RDB Board Board: LS1046ARDB, boot from Invalid setting of SW5 CPLD: V0.0 PCBA: V0.0 SERDES Reference Clocks: SD1_CLK1 = 100.00MHZ, SD1_CLK2 = 100.00MHZ I2C: ready DRAM: wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x36 retry=0 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x36 retry=1 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x36 retry=2 i2c_init_transfer: give up i2c_regs=0x2180000 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x51 retry=0 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x51 retry=1 wait_for_sr_state: failed sr=a1 cr=38 state=202 i2c_init_transfer: failed for chip 0x51 retry=2 i2c_init_transfer: give up i2c_regs=0x2180000 DDR: failed to read SPD from address 81 Error: No valid SPD detected. 16 EiB (DDR not enabled) "Synchronous Abort" handler, esr 0x96000045 ELR: fff638e8 LR: ffefd214 x0 : 00000007ffe00000 x1 : 0000000000000000 x2 : 0000000000001000 x3 : 00000007ffe01000 x4 : 00000007ffe00000 x5 : 0000000000000000 x6 : 00000000000001e8 x7 : 0000000000000001 x8 : 0000000082070550 x9 : 000000007defb000 x10: 0000000000000403 x11: 0000000082059274 x12: 0000000000000002 x13: 0000000000000000 x14: 0000000000000000 x15: 0000000082003228 x16: 0000000000000000 x17: 0000000000000000 x18: 00000000ffdf8d70 x19: 00000007ffe00000 x20: 00000007ffe00000 x21: 0000000000000000 x22: 00000000fff89490 x23: 0000000000000000 x24: 0000000000000000 x25: 0000000000000000 x26: 0000000000000000 x27: 0000000000000000 x28: 0000000082001cd8 x29: 00000000ffdf6680 Resetting CPU ... resetting ... guts: Unknown register read: b0 guts: Unknown register write: b0 = 2
最終的には Abort してしまっているけど、原因がどこかは現時点では未調査。
タイムアウトの原因を GDB で追いかけると、 i2c_init_transfer_()
から tx_byte()
に入り、 I2DR にスレーブアドレスを書き込んだあとに、 I2SR_IIF ビット (割り込み) が立たないため、タイムアウトが発生していた。
Qemu 側も GDB で追いかけると、imx_i2c.c から i2c/core.c の i2c_start_transfer()
を呼び出したところで QTAILQ_FOREACH()
マクロの処理が行われていないため、 I2SR_IIF ビットを立てる処理が実施されていないことがわかった。
QTAILQ_FOREACH()
マクロは、 &bus->qbus.children.tqh_first
にデータがある場合に実行される処理で、タイムアウトの場合は NULL となっていたため、 bus->current_devs.lh_first
も空のままになり、下の QLIST_EMPTY で return 1 となっていた。
if (QLIST_EMPTY(&bus->current_devs)) { QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { DeviceState *qdev = kid->child; I2CSlave *candidate = I2C_SLAVE(qdev); if ((candidate->address == address) || (bus->broadcast)) { node = g_malloc(sizeof(struct I2CNode)); node->elt = candidate; QLIST_INSERT_HEAD(&bus->current_devs, node, next); if (!bus->broadcast) { break; } } } bus_scanned = true; } if (QLIST_EMPTY(&bus->current_devs)) { return 1; }
bus->qbus.children.tqh_first
にデータが入る条件を調べると、 qdev_set_parent_bus()
が呼ばれた場合であることがわかった。
qdev_set_parent_bus()
は、システムバズに仮想デバイスをつなぐ場合に呼び出している処理で、特定のバスに仮想デバイスを接続する機能を持っている。
ということは、現在は i2c バスにデバイスが接続されていないから、スレーブアドレスの書き込みでタイムアウトになっている、ということ?
backtrace を確認すると、 DDR の SPD アクセスに使用していることがわかった。
DDR の情報が取得できないので、 Abort につながっているようだ。
U-Boot (aarch64) on Qemu を動作させたい (5)
u-boot.bin をダンプすると、 init_sequence_f のアドレスには関数ポインタが格納されていることを確認した。
0004cb70 1c 07 09 00 00 00 00 00 48 9c 09 00 00 00 00 00 |........H.......| 0004cb80 00 08 09 00 00 00 00 00 38 2d 08 00 00 00 00 00 |........8-......| 0004cb90 d4 08 09 00 00 00 00 00 08 08 09 00 00 00 00 00 |................| 0004cba0 b8 08 09 00 00 00 00 00 34 34 08 00 00 00 00 00 |........44......| 0004cbb0 e8 4e 0b 00 00 00 00 00 44 27 09 00 00 00 00 00 |.N......D'......|
(gdb) p setup_mon_len $1 = {int (void)} 0x9071c <setup_mon_len> (gdb) p initf_malloc $2 = {int (void)} 0x99c48 <initf_malloc> (gdb) p initf_console_record $4 = {int (void)} 0x90800 <initf_console_record>
と、ここで気づいたが、エラーになるからと、 u-boot.bin ではなく、 u-boot (elf) を -kernel に渡していたが、結構ファイルサイズが違うことに気づく。
もしかして、と、 u-boot の init_sequence_f あたりをダンプすると、
0005cb70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 0005cd70 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 |................| 0005cd80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0005cd90 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................| 0005cda0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
なんか、すごく見覚えがあるデータ配置 (ところどころの 1 具合が) 出たので、間違いない気がする。
CONFIG_REMAKE_ELF を追加して、 u-boot.elf を作成し、同じアドレスをダンプすると、
0005cb70 1c 07 09 00 00 00 00 00 48 9c 09 00 00 00 00 00 |........H.......| 0005cb80 00 08 09 00 00 00 00 00 38 2d 08 00 00 00 00 00 |........8-......| 0005cb90 d4 08 09 00 00 00 00 00 08 08 09 00 00 00 00 00 |................|
となり、期待通りの結果になった!
エラーは残っているものの、無事、 U-Boot (aarch64) on Qemu を動作させることができた。 u-boot / qemu の動作およびデバッグについてもいい勉強になった。
U-Boot 2016.09-dirty (Oct 10 2017 - 04:57:49 +0900) [51/18819] DRAM: 960 MiB RPI 3 Model B (0xa32081) MMC: bcm2835_sdhci: 0 Card did not respond to voltage select! ** Bad device mmc 0 ** Using default environment In: serial Out: lcd Err: lcd Net: Net Initialization Skipped No ethernet found. starting USB... USB0: Core Release: 0.000 SNPSID invalid (not DWC2 OTG device): 00000000 Port not available. Hit any key to stop autoboot: 0 Card did not respond to voltage select! starting USB... USB0: Core Release: 0.000 [25/18819] SNPSID invalid (not DWC2 OTG device): 00000000 Port not available. No ethernet found. missing environment variable: pxeuuid missing environment variable: bootfile Retrieving file: pxelinux.cfg/00000000 No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/0000000 No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/000000 No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/00000 No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/0000 No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/000 [4/18819] No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/00 No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/0 No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/default-arm-bcm283x No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/default-arm No ethernet found. missing environment variable: bootfile Retrieving file: pxelinux.cfg/default No ethernet found. Config file not found starting USB... USB0: Core Release: 0.000 SNPSID invalid (not DWC2 OTG device): 00000000 U-Boot> print arch=arm baudrate=115200 board=rpi board_name=3 Model B board_rev=0x8 board_rev_scheme=1 board_revision=0xA32081
ただ、 UART については raspi3 で有効になる CONFIG_BCM283X_MU_SERIAL の動かし方がわからないので CONFIG_PL01X_SERIAL を有効にしてしのいでいる。
/* Console UART */ #ifdef CONFIG_BCM2837 -#define CONFIG_BCM283X_MU_SERIAL +#define CONFIG_PL01X_SERIAL #else #define CONFIG_PL01X_SERIAL #endif
U-Boot (aarch64) on Qemu を動作させたい (4)
更に処理を追いかけると、 board_init_f()
(common/board_f.c) で static に取られた変数の init_sequence_f
のデータが空になっていることがわかった。。
本来は、ボードの初期化メソッドのテーブルなので、関数ポインタが入っているべきところ。
どゆこと??
board_init_f (boot_flags=0) at common/board_f.c:1072 1072 gd->flags = boot_flags; (gdb) 1075 if (initcall_run_list(init_sequence_f)) (gdb) 1073 gd->have_console = 0; (gdb) 1075 if (initcall_run_list(init_sequence_f)) (gdb) p init_sequence_f $1 = {0x0 <repeats 37 times>}
再び、 xilinx_zcu102 で確認すると、
_start () at arch/arm/cpu/armv8/start.S:22 22 b reset Breakpoint 1 at 0x8000000: file arch/arm/cpu/armv8/start.S, line 22. Breakpoint 2 at 0x8002be8: file arch/arm/lib/crt0_64.S, line 75. (gdb) x/32 init_sequence_f 0x8072588 <init_sequence_f>: 134298688 0 134533344 0 0x8072598 <init_sequence_f+16>: 134333800 0 134298840 0 0x80725a8 <init_sequence_f+32>: 134299264 0 134299100 0 0x80725b8 <init_sequence_f+48>: 134298848 0 134299072 0 0x80725c8 <init_sequence_f+64>: 134543948 0 134307552 0 0x80725d8 <init_sequence_f+80>: 134299012 0 134413964 0 0x80725e8 <init_sequence_f+96>: 134329008 0 134532500 0 0x80725f8 <init_sequence_f+112>: 134537568 0 134299256 0
動かす前からちゃんと展開されているので、 Qemu 側が firm を正しく展開できていない気配も出てきた。
U-Boot (aarch64) on Qemu を動作させたい (3)
確認していくと、どうやら u-boot の _start (arch/arm/cpu/armv8/start.S:22) がちゃんと処理されていることが確認できた。
確認手順は、
$ qemu-system-aarch64 \ -S -gdb tcp::1234 \ -machine $MACHINE \ -kernel u-boot/u-boot \ -nographic
してから、
$ aarch64-linux-gnu-gdb u-boot ... Reading symbols from u-boot...done. (gdb) target remote localhost:1234 Remote debugging using localhost:1234 _start () at arch/arm/cpu/armv8/start.S:22 22 b reset
で OK。
u-boot の動きを追いかけると、、、
board_init_f (boot_flags=<optimized out>) at common/board_f.c:1083
までは動作していて、
relocate_code () at arch/arm/lib/relocate_64.S:24 24 mov x29, sp (gdb) s 25 str x0, [sp, #16] (gdb) s 29 ldr x1, =__image_copy_start /* x1 <- SRC &__image_copy_start */ (gdb) p __image_copy_start $6 = 0x80000 <_start> "\n"
リロケーションも上手く行っているように見えるが、、、
relocate_code()
を抜けるとハングしているので、リロケーションが上手くできていない??
relocate_code () at arch/arm/lib/relocate_64.S:76 76 ret (gdb) s ^C Thread 1 received signal SIGINT, Interrupt. 0x0000000000000000 in ?? () (gdb) bt #0 0x0000000000000000 in ?? () #1 0x0000000000000000 in ?? () Backtrace stopped: not enough registers or memory available to unwind further
直前のコードで怪しそうなのは、、、
26 /* 27 * Copy u-boot from flash to RAM 28 */ 29 ldr x1, =__image_copy_start /* x1 <- SRC &__image_copy_start */ 30 subs x9, x0, x1 /* x9 <- relocation offset */ 31 b.eq relocate_done /* skip relocation */ 32 ldr x2, =__image_copy_end /* x2 <- SRC &__image_copy_end */ 33 34 copy_loop: 35 ldp x10, x11, [x1], #16 /* copy from source address [x1] */
で、実際の処理は b.eq で relocate_done にジャンプしており、コピーが行われていない。 (正しくはコピーが行われるべき??)
__image_copy_start は
(gdb) p __image_copy_start $1 = 0x80000 <_start> "\n" (gdb) p/x *(__image_copy_start + 0) $14 = 0xa (gdb) p/x *(__image_copy_start + 1) $15 = 0x0 (gdb) p/x *(__image_copy_start + 2) $16 = 0x0 (gdb) p/x *(__image_copy_start + 3) $17 = 0x14 (gdb) p/x *(__image_copy_start + 4) $18 = 0x1f (gdb) p/x *(__image_copy_start + 5) $19 = 0x20 (gdb) p/x *(__image_copy_start + 6) $20 = 0x3 (gdb) p/x *(__image_copy_start + 7) $21 = 0xd5
となっており、 u-boot.bin のデータが先頭から配置されていた。
レジスタの状態はというと、
x0 0x0 0 x1 0x0 0 x2 0x0 0 x3 0x0 0 x4 0x0 0 x5 0x2e 46 x6 0x170 368 x7 0x0 0 x8 0x0 0 x9 0x0 0
となっており、 subs x9, x0, x1
で x9 が 0 になったため、 b.eq で relocate_done にジャンプする結果になったようだ。
relocate_code()
の処理を真面目に追いかけると、
16 /* 17 * void relocate_code (addr_moni) 18 * 19 * This function relocates the monitor code. 20 * x0 holds the destination address. 21 */ 22 ENTRY(relocate_code) # x29 0x80088 524424 # x30 0x82588 533896 # sp 0x0 0x0 # pc 0x825d0 0x825d0 <relocate_code> 23 stp x29, x30, [sp, #-32]! /* create a stack frame */ /** つまり、 x29 および x30 のデータを [sp, #-32] に push している? */ # STP Xt1, Xt2, [Xn|SP, #imm]! ; 64 ビット汎用レジスタ、プレインデクス # Xt1 転送される最初の汎用レジスタ(64 ビット)名を 0 ~ 31 の範囲内で指定します。 # Xt2 転送される 2 つ目の汎用レジスタ(64 ビット)名を 0 ~ 31 の範囲内で指定します。 # Xn|SP 64 ビットの汎用ベースレジスタ名またはスタックポインタ名を 0 ~ 31 の範囲内で指定します。 # imm 64 ビット汎用レジスタ。 # ポストインデクスおよびプレインデクスバリアントは符号付きイミディエートバイトのオフセットであるため、 # -512 ~ 504 の範囲で 8 の倍数となります。 # 符号付きオフセットバリアントはオプションの符号付きイミディエートバイトのオフセットであるため、 # -512 ~ 504 の範囲で 8 の倍数で指定します。デフォルトで 0 になります。 # x29 0x80088 524424 # x30 0x82588 533896 # sp 0xffffffffffffffe0 0xffffffffffffffe0 /** sp が負数って良いの?? */ # pc 0x825d4 0x825d4 <relocate_code+4> 24 mov x29, sp /** x29 = sp */ # x29 0xffffffffffffffe0 -32 # x30 0x82588 533896 # sp 0xffffffffffffffe0 0xffffffffffffffe0 # pc 0x825d8 0x825d8 <relocate_code+8> 25 str x0, [sp, #16] /** x0 = *(sp + 16) */ 26 /* 27 * Copy u-boot from flash to RAM 28 */ # x0 0x0 0 # x1 0x0 0 # x29 0xffffffffffffffe0 -32 # x30 0x82588 533896 # sp 0xffffffffffffffe0 0xffffffffffffffe0 # pc 0x825dc 0x825dc <relocate_code+12> 29 ldr x1, =__image_copy_start /* x1 <- SRC &__image_copy_start */ # x0 0x0 0 # x1 0x0 0 # x29 0xffffffffffffffe0 -32 # x30 0x82588 533896 # sp 0xffffffffffffffe0 0xffffffffffffffe0 # pc 0x825e0 0x825e0 <relocate_code+16> 30 subs x9, x0, x1 /* x9 <- relocation offset */ 31 b.eq relocate_done /* skip relocation */
雰囲気は、 L25 の str の結果 (x0) と L29 の ldr の結果 (x1) が 0 になっているのがおかしい気がする。
そもそも、 L23 の stp の結果がスタックにちゃんと入っていない気がする。。
(gdb) x/8 -32 0xffffffffffffffe0: 0x00000000 0x00000000 0x00000000 0x00000000 0xfffffffffffffff0: 0x00000000 0x00000000 0x00000000 0x00000000
ちなみに、期待通り動作している xilinx_zcu102 では、
x29 0x8000090 134217872 x30 0x7ff1fc30 2146565168 sp 0x7df1adb0 0x7df1adb0 pc 0x8002c7c 0x8002c7c <relocate_code+4> (gdb) x/8 0x7df1adb0 0x7df1adb0: 134217872 0 2146565168 0 0x7df1adc0: 0 0 0 0
うん、期待通り SP のアドレスに x29 と x30 が push されている。
ということは、 raspi3 の場合に SP が 0 になっていることが問題の原因??
解析を続けると、 arch/arm/lib/crt0_64.S で SP が 0 になる処理を発見した。
88 #if !defined(CONFIG_SPL_BUILD) 89 /* 90 * Set up intermediate environment (new sp and gd) and call 91 * relocate_code(addr_moni). Trick here is that we'll return 92 * 'here' but relocated. 93 */ 94 ldr x0, [x18, #GD_START_ADDR_SP] /* x0 <- gd->start_addr_sp */ 95 bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */
L94 で x0 に 0 が入り、 L95 で sp = x0 が行われていた。
先ほどと同じく、 xilinx_zcu102 で確認すると、
94 ldr x0, [x18, #GD_START_ADDR_SP] /* x0 <- gd->start_addr_sp */ (gdb) info register sp x0 x18 sp 0x7ff7e90 0x7ff7e90 x0 0x0 0 x18 0x7ff7e90 134184592 (gdb) s 95 bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */ (gdb) info register sp x0 x18 sp 0x7ff7e90 0x7ff7e90 x0 0x7df1add0 2112990672 x18 0x7ff7e90 134184592 (gdb) x/32 0x7ff7e90 0x7ff7e90: 0x7df1af58 0x00000000 0x00000100 0x00000000 0x7ff7ea0: 0x0001c200 0x00000000 0x00000000 0x00000000 0x7ff7eb0: 0x00000000 0x00000000 0x00000000 0x00000000 0x7ff7ec0: 0x00000000 0x00000000 0x00000001 0x00000000 0x7ff7ed0: 0x08057220 0x00000000 0x00000000 0x00000000 0x7ff7ee0: 0x80000000 0x00000000 0x7ff1d000 0x00000000 0x7ff7ef0: 0x80000000 0x00000000 0x000c2d20 0x00000000 0x7ff7f00: 0x7df1add0 0x00000000 0x7df1add0 0x00000000
やはり L94 で x0 に適切な値が代入されていた。 ( x0 = *(x18 + 0x70))
それで、 raspi3 はというと、、、
(gdb) s 95 bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */ (gdb) info register sp x0 x18 sp 0x7ffdd20 0x7ffdd20 x0 0x0 0 x18 0x7ffdd20 134208800 (gdb) x/32 0x7ffdd20 0x7ffdd20: 0 0 0 0 0x7ffdd30: 0 0 0 0 0x7ffdd40: 0 0 0 0 0x7ffdd50: 0 0 0 0 0x7ffdd60: 0 0 0 0 0x7ffdd70: 0 0 0 0 0x7ffdd80: 0 0 0 0 0x7ffdd90: 0 0 0 0
コードを見ると、 x18 には global_data が入っているのが期待動作らしく、 raspi3 のように global_data がオール 0 というのはやはりおかしそう。
global_data の処理を追いかければ、何かヒントがみつかるかも??
U-Boot (aarch64) on Qemu を動作させたい (2)
とりあえず、期待通り U-Boot の entry point である 0x80000 (_start) に制御が移っているのか?ということの確認を目指してみる。
gdb --args qemu-system-aarch64 -machine raspi3 -kernel u-boot/u-boot -nographic
途中 (qemu/boot.c) に
/* Assume that raw images are linux kernels, and ELF images are not. */
kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr,
&elf_high_addr, elf_machine);
というコメントもあったので、読み込むバイナリは elf (≠ u-boot.bin) で問題なさそう。 (事実 is_linux フラグは false となる)
arm_load_kernel_notify()
あたりまで u-boot の読み込み処理を追いかけた結果、ファイルのロードや entry point が 0x80000 となることなどは期待通り動作していそう。
次は、リセット時に entry point にジャンプできているか見ていく。
`do_cpu_reset()' (qemu/boot.c) に break point を設定して追いかけてみる。
do_cpu_reset()
から aarch64_cpu_set_pc()
が呼ばれて、 env.pc
に entry point (0x80000) が設定されていることは確認できた。
ここからがわからない。。 qemu/target/arm/machine.c や qemu/target/arm/translate-a64.c あたりに処理が移るのか?実際に PC を処理しているところはどこだろう??
U-Boot (aarch64) on Qemu を動作させたい (1)
なんとか、動作させるまで漕ぎ着けたいな。。
現状は以下のような状態です。
qemu-system-aarch64 -M raspi2 -cpu cortex-a53 -kernel u-boot ...
(u-boot with rpi_3_defconfig) は全く(?) 動作していないっぽい。- 同じ aarch64 (cortex-a53) の xlinx-zcu102 (
qemu-system-aarch64 -M xlnx-zcu102 -kernel u-boot.elf -nographic -m 2G -drive file=u-boot,id=d,if=none -device ide-drive,drive=d,bus=ide.0
) は起動しているので、 qemu / u-boot 自体に問題があるわけではなさそう。
どうすれば raspi3 向け U-Boot を qemu-system-aarch64 で動作させるところまでたどり着けるかは検討ついていませんが、とりあえず手を動かしてみる。
qemu 上でどこまで動作しているのかを知る
qemu-system-aarch64 に gdb をつないでどこまで動作しているか見てみる。
qemu-system-aarch64 \ -S \ -gdb tcp::1234 \ -M raspi2 \ -cpu cortex-a53 \ -kernel u-boot/u-boot \ -nographic \
$ aarch64-linux-gnu-gdb (gdb) target remote localhost:1234 Remote debugging using localhost:1234 warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x00000000 in ?? () (gdb) bt #0 0x00000000 in ?? () (gdb) c Continuing. ^C Thread 1 received signal SIGINT, Interrupt. 0x00000004 in ?? () (gdb) bt #0 0x00000004 in ?? ()
さすがにアドレス 0x4 はまったく動いている気配がしない。
仕事で基板立ち上げにほとんど関わった経験もないから、疑わしいところの検討もつかないな、これは。
qemu がどのように動作しているのか知る
を参考に、 qemu 側から現在の動作状態を調査してみる。 (u-boot のバイトコードがどこまで処理されているかがわかれば、見直すポイントを知る手助けになるかなーという期待から)
qemu コンソールから info qom-tree
を確認すると、 CPU が cortex-a15 となっていた。
(qemu) info qom-tree / ... /machine (raspi2-machine) /peripheral (container) /ram[0] (qemu:memory-region) /soc (bcm2836) /cpu[0] (cortex-a15-arm-cpu)
コンソールからの -cpu cortex-a53
は無視されている??
取り急ぎ、 raspi2 / bcm2836 のコードをコピペして raspi3 / bcm2837 を作成して解析を続行する。
Das U-Boot on Qemu (aarch64) を動かしてみる
U-Boot を aarch64 emulated by Qemu な環境で動作させることができるか試してみる。
Qemu のビルド
まずは、 Qemu をビルドしてみる。
### とりあえず、現状最新の v2.10.1 で試してみる。 $ git clone git://git.qemu.org/qemu.git $ cd qemu $ git checkout -b v2.10.1-release refs/tags/v2.10.1 $ git submodule update --init ### arm と aarch64 を有効にする。 ### あと、 raspberry pi にあわせてオーディオは alsa にしておく。 (無指定の場合は oss になるため) $ ./configure --prefix=`pwd`/build --target-list=arm-softmmu,aarch64-softmmu --audio-drv-list=alsa $ make $ make install
U-Boot のビルド
つづいて、 U-Boot のビルドを行う。
U-Boot はターゲット上で動作するため、 aarch64 向けにビルドする必要がある。
手っ取り早く、 Linaro のツールチェインを入れる。
### クロスコンパイラをダウンロードする。 $ curl -L https://releases.linaro.org/components/toolchain/binaries/latest-5/aarch64-linux-gnu/gcc-linaro-5.4.1-2017.05-x86_64_aarch64-linux-gnu.tar.xz | tar xJ ### runtime & sysroot をダウンロードする。 (必要?) $ curl -L https://releases.linaro.org/components/toolchain/binaries/latest-5/aarch64-linux-gnu/runtime-gcc-linaro-5.4.1-2017.05-aarch64-linux-gnu.tar.xz | tar xJ $ curl -L https://releases.linaro.org/components/toolchain/binaries/latest-5/aarch64-linux-gnu/sysroot-glibc-linaro-2.21-2017.05-aarch64-linux-gnu.tar.xz | tar xJ ### クロスコンパイラへのパスを通しておく。 $ export PATH=`pwd`/gcc-linaro-5.4.1-2017.05-x86_64_aarch64-linux-gnu/bin:$PATH
### こちらは、諸事情で v2016.09 を使用する。 $ git clone git://git.denx.de/u-boot.git $ cd u-boot $ git checkout -b v2016.09 refs/tags/v2016.09 ### とりあえず aarch64 を利用している raspberry pi3 で試す。 $ make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- rpi_3_defconfig $ make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu-
だめでした
まともに起動はしないにしても、何かしらのログは出てくれるかなーと思ったけど、沈黙しかそこにはありませんでした。。
### raspi2 をベースに cortex-a53 を cpu に指定して動かす。 (ちなみに u-boot.bin も同様に動かなかった。) $ qemu/build/bin/qemu-system-aarch64 -M raspi2 -cpu cortex-a53 -nographic -kernel u-boot/u-boot
32bit 版は起動はする
同じ raspberry pi3 向けの u-boot でも、 32bit 版はログは出た。
### u-boot のビルド。 $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- rpi_3_32b_defconfig $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- $ file u-boot u-boot: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), not stripped
### qemu のオプションは同じ。 $ qemu/build/bin/qemu-system-aarch64 -M raspi2 -cpu cortex-a53 -nographic -kernel u-boot/u-boot U-Boot 2016.09-dirty (Oct 05 2017 - 00:58:21 +0900) DRAM: 960 MiB RPI 2 Model B (0xa21041) MMC: ### ここでフリーズ
Qemu で aarch64 な U-Boot を動かすには、何から手を付ければよいものやら。。。