明日にはでっかい太陽が昇るかもしれません。

「覚悟」とは!! 暗闇の荒野に!!進むべき道を切り開く事だッ!

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 を確認すると、 DDRSPD アクセスに使用していることがわかった。

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) に制御が移っているのか?ということの確認を目指してみる。

qemu 自体を gdb で解析してみる。

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)

なんとか、動作させるまで漕ぎ着けたいな。。

現状は以下のような状態です。

  1. qemu-system-aarch64 -M raspi2 -cpu cortex-a53 -kernel u-boot ... (u-boot with rpi_3_defconfig) は全く(?) 動作していないっぽい。
  2. 同じ 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 がどのように動作しているのか知る

rkx1209.hatenablog.com

を参考に、 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 を動かすには、何から手を付ければよいものやら。。。