[失敗] pcDuinoでFreeBSD 其の壱

千石通商で処分品の箱にあったpcDuinoを買ってきたので、FreeBSDを試してみます。

こののターゲットはAllwinterのA10というSOCが使われています。我が家で初のarmv7系です。またまた一周遅れで自分らしいです。

Allwinnerのサポートは10Rで入ってA10は初期のターゲットだったようです。A10のターゲットはcubieboardというボードだったようです。

https://wiki.freebsd.org/FreeBSD/arm/Cubieboard

pcDuinoはCFIなFlashが実装されているようですが、Liteはパターンはあるけど実装されてなくて、SDからブートするようです。pcDuinoはSDからFlashにLinuxをコピーしてブートするようですが、Liteについては資料が見当たりませんでした。このため一旦Linuxを試そうと思ったのですがあきらめました。

このターゲットでFreeBSDを起動する方法は二つあり、u-bootから直接カーネルを起動する方法とu-bootからubldrを起動してそこからカーネルを起動する方法になります。

公式のimgは後者でつくられているのですが、ZRouterでのビルドを行うので、前者で試そうと思います。

まずはu-bootをSDに用意します。

手持ちのSDのGPTな設定がFreeBSDでは消せなかったので、MacでMBRのFATでフォーマットしてみました。(gpart destroy -F da0すればよかったみたいです)

```
% gpart show da0
=>       1  15661055  da0  MBR  (7.5G)
         1         1       - free -  (512B)
         2  15661054    1  fat32  (7.5G)

```

一旦FAT部分を消します。

```
% sudo gpart delete -i 1 da0
da0s1 deleted
% gpart show da0
=>       1  15661055  da0  MBR  (7.5G)
         1  15661055       - free -  (7.5G)

```

splとu-bootを書き込みます。

```
% sudo pkg install u-boot-cubieboard
% cd /usr/local/share/u-boot/u-boot-cubieboard
% sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/da0 bs=1k seek=8 conv=sync
```

FAT部分を作ります。

```
% sudo gpart add -b 1m -s 24m -t '\!12' /dev/da0
da0s1 added
% sudo gpart set -a active -i 1 /dev/da0
active set on da0s1
% sudo newfs_msdos -L boot -F 16 /dev/da0s1
/dev/da0s1: 48992 sectors in 6124 FAT16 clusters (4096 bytes/cluster)
BytesPerSec=512 SecPerClust=8 ResSectors=1 FATs=2 RootDirEnts=512 Sectors=49077 Media=0xf0 FATsecs=24 SecPerTrack=63 Heads=255 HiddenSecs=0
```

本体にシリアル接続して115200でターミナルを上げて出来上がった、SDを差して起動します。

シリアル接続はここです。

![513a747ace395fa928000000.png](https://qiita-image-store.s3.amazonaws.com/0/104066/00400efa-fac5-77e8-5265-41f3d06f6462.png)

起動すると以下のような表示がでます。HDMIにも表示は出ますが、入力はシリアルなので、ターミナルでオペレーションをするのがよいでしょう。

```
U-Boot SPL 2018.09 (Oct 26 2018 - 02:52:54 +0000)
DRAM: 512 MiB
CPU: 1008000000Hz, AXI/AHB/APB: 3/2/2
Trying to boot from MMC1


U-Boot 2018.09 (Oct 26 2018 - 02:52:54 +0000) Allwinner Technology

CPU:   Allwinner A10 (SUN4I)
Model: Cubietech Cubieboard
I2C:   ready
DRAM:  512 MiB
MMC:   mmc@01c0f000: 0
Loading Environment from FAT... OK
HDMI connected: Setting up a 1920x1080 hdmi console (overscan 0x0)
In:    serial
Out:   vga
Err:   vga
Net:   eth0: ethernet@01c0b000
starting USB...
USB0:   USB EHCI 1.00
USB1:   USB OHCI 1.0
USB2:   USB EHCI 1.00
USB3:   USB OHCI 1.0
scanning bus 0 for devices... 1 USB Device(s) found
scanning bus 2 for devices... 1 USB Device(s) found
```

このターゲットはシリアルを接続しなおして起動しないと起動しませんでした。USBモジュールとの相性なのかもしれません。

ZRouterを使い先日13になったばかりのheadでカーネルをビルドできるように調整します。

カーネルがビルドできたら、エントリーアドレスを確認します。0xc0200180から0x40200180となります。

```
% readelf -h Pcduino_Lite_kernel | grep "Entry point address"
  Entry point address:               0xc0200180
```

とりあえずブートしてみるが何も起こらない

```
=> fatload mmc 0 0x40200000 kernel; go 0x40200180
3728916 bytes read in 305 ms (11.7 MiB/s)
## Starting application at 0x40200180 ...
```

u-bootでuartの確認

```
=> mw.b 0x01c28000 0x55
U=> 
```

locore-v6.Sに以下のコードを入れて確認

```
ldr     r0,=0x01c28000
ldr     r2,=0x55
strb    r2, [r0]
```

実行は移っているみたい。

```
=> fatload mmc 0 0x40200000 kernel; go 0x40200180
3728916 bytes read in 305 ms (11.7 MiB/s)
## Starting application at 0x40200180 ...
U
```

未定義命令の.byte 0xFF, 0xFF, 0xFF, 0xFFを入れても確認できます。

```
## Starting application at 0x40200180 ...
undefined instruction
pc : [<40200180>]	   lr : [<5ef69777>]
reloc pc : [<2b299180>]	   lr : [<4a002777>]
sp : 5af3f098  ip : 5efb283c	 fp : 00000002
r10: 5efb5410  r9 : 5af46ed8	 r8 : 5af5be78
r7 : 5ef6974d  r6 : 00000002	 r5 : 40200180  r4 : 5af5be7c
r3 : 40200180  r2 : 00000006	 r1 : 5af5be7c  r0 : 00000001
Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
Code: 00000000 00000000 00000000 00000000 (ffffffff) 
Resetting CPU ...

resetting ...
```

とりあえずEARLY_PRINTFを使ってカーネルをビルドしてみます。

変わりません。。。~~コードを見るとbuild_pagetablesとbuild_device_pagetablesが同じ処理になっていて意味無く、壊れているっぽいです。~~問題は他のようです。

思ったより手こずるので、ビルドの度にSDに焼いてだと手間がかかるので、ネットワークで確認できるようにしてみた。2018.09のビルドのu-bootはネットワークがちゃんと使えました。

```
=> setenv ipaddr 10.10.10.111
=> setenv serverip 10.10.10.3
=> tftpboot 0x40200000 Pcduino_Lite_kernel
Using ethernet@01c0b000 device
TFTP from server 10.10.10.3; our IP address is 10.10.10.111
Filename 'Pcduino_Lite_kernel'.
Load address: 0x40200000
Loading: #################################################################
	 #################################################################
	 #################################################################
	 ############################################################
	 599.6 KiB/s
done
Bytes transferred = 3729184 (38e720 hex)
=> go 0x40200180
## Starting application at 0x40200180 ...
```

試しに11.2RのimgをSDに焼いてみたのですが起動しません。。。

```
U-Boot SPL 2018.03 (Jun 22 2018 - 00:42:02 +0000)
DRAM: 512 MiB
CPU: 1008000000Hz, AXI/AHB/APB: 3/2/2
Trying to boot from MMC1


U-Boot 2018.03 (Jun 22 2018 - 00:42:02 +0000) Allwinner Technology

CPU:   Allwinner A10 (SUN4I)
Model: Cubietech Cubieboard
I2C:   ready
DRAM:  512 MiB
MMC:   SUNXI SD/MMC: 0
Loading Environment from FAT... *** Warning - bad CRC, using default environment

Failed (-5)
Loading Environment from MMC... *** Warning - bad CRC, using default environment

Failed (-5)
HDMI connected: Setting up a 1920x1080 hdmi console (overscan 0x0)
In:    serial
Out:   vga
Err:   vga
SCSI:  AHCI PHY power up failed.
Net:   eth0: ethernet@01c0b000
starting USB...
USB0:   USB EHCI 1.00
USB1:   USB OHCI 1.0
USB2:   USB EHCI 1.00
USB3:   USB OHCI 1.0
scanning bus 0 for devices... 1 USB Device(s) found
scanning bus 2 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Hit any key to stop autoboot:  0 
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found U-Boot script /boot.scr
199 bytes read in 13 ms (14.6 KiB/s)
## Executing script at 43100000
235476 bytes read in 42 ms (5.3 MiB/s)
## Starting application at 0x42000000 ...
Consoles: U-Boot console  
Compatible U-Boot API signature found @0x5af4d3c0

FreeBSD/armv6 U-Boot loader, Revision 1.2
(Fri Jun 22 01:54:49 UTC 2018 root@releng2.nyi.freebsd.org)

DRAM: 512MB
MMC Device 1 not found
MMC Device 2 not found
MMC Device 3 not found
Number of U-Boot devices: 1
U-Boot env: loaderdev not set, will probe all devices.
Found U-Boot device: disk
  Probing all disk devices...
  Checking unit=0 slice=<auto> partition=<auto>... good.
Booting from disk0s2a:
Loading /boot/defaults/loader.conf
/boot/kernel/kernel data=0x63932c+0x4acd4 syms=[0x4+0x6b630+0x4+0x9a638]
-
Hit [Enter] to boot immediately, or any other key for command prompt.
Booting [/boot/kernel/kernel]...               
No valid device tree blob found!

Type '?' for a list of commands, 'help' for more detailed help.
loader> 
```

13-CURRENTのスナップショットのimgはkernelは起動しますがパニックしました。

いろいろ試したところ、mapしてuartに書けるようになりました。

```
        uint8_t *tx = (uint8_t *)0xf1c28000;
        *tx = '1';
```

これで確認したら、OF_install()がエラーを起こしているようです。

OF_install()はdev/ofw/openfirm.cにあって、引数のofw_fdtというkbojを探すようです。

OFW_DEF()というマクロでofw_fdtがofw_setにセットされるようで、それを探しに行くのが本来の流れのようです。

初期のarmのブートの話はここに書いてありました。

https://wiki.freebsd.org/FreeBSD/arm/BootProcess

OF_install()を逆アセンブルするとこんな風です。

```
c0236e4c:       e30175d4        movw    r7, #5588       ; 0x15d4
c0236e50:       e30145d0        movw    r4, #5584       ; 0x15d0
c0236e54:       e3a08000        mov     r8, #0  ; 0x0
c0236e58:       e34c7046        movt    r7, #49222      ; 0xc046
c0236e5c:       e34c4046        movt    r4, #49222      ; 0xc046
c0236e60:       e1540007        cmp     r4, r7
c0236e64:       2a000023        bcs     c0236ef8 <OF_install+0xc8>
c0236e68:       e3085000        movw    r5, #32768      ; 0x8000
c0236e6c:       e34f51c2        movt    r5, #61890      ; 0xf1c2
c0236e70:       e5949000        ldr     r9, [r4]
c0236e74:       e5990000        ldr     r0, [r9]
c0236e78:       e3500000        cmp     r0, #0  ; 0x0
c0236e7c:       0a00000d        beq     c0236eb8 <OF_install+0x88>
c0236e80:       e5d00000        ldrb    r0, [r0]
c0236e84:       e5c50000        strb    r0, [r5]
c0236e88:       e5990000        ldr     r0, [r9]
c0236e8c:       e3500000        cmp     r0, #0  ; 0x0
c0236e90:       0a000008        beq     c0236eb8 <OF_install+0x88>
c0236e94:       e1a01006        mov     r1, r6
c0236e98:       eb04d9a7        bl      c036d53c <strcmp>
```

readelfで見るとこんな風です。

```
% readelf -a Pcduino_Lite_kernel | grep _set_ofw_set
  2393: c04615d4     0 NOTYPE  GLOBAL DEFAULT    6 __stop_set_ofw_set
  6355: c04615d0     0 NOTYPE  GLOBAL DEFAULT    6 __start_set_ofw_set
  1015: c04615d0     4 OBJECT  LOCAL  DEFAULT    6 __set_ofw_set_sym_ofw_fdt
 11402: c04615d0     0 NOTYPE  GLOBAL DEFAULT    6 __start_set_ofw_set
 11403: c04615d4     0 NOTYPE  GLOBAL DEFAULT    6 __stop_set_ofw_set
```

中身はこんなです。

```
c04615d0 <__start_set_ofw_set>:
c04615d0:       c04d1c4c        subgt   r1, sp, ip, asr #24
Disassembly of section set_uart_fdt_class_and_device_set:

c04615d4 <__start_set_uart_fdt_class_and_device_set>:
c04615d4:       c04d2804        subgt   r2, sp, r4, lsl #16
Disassembly of section set_uart_fdt_class_set:
```
ちゃんと__start_set_ofw_setを参照しているように見れます。

その先はこんなです。

```
c04d1c4c <ofw_fdt>:
c04d1c4c:       c0440595        umaalgt r0, r4, r5, r5
c04d1c50:       c0459028        subgt   r9, r5, r8, lsr #32
        ...
```

コードはこんなです。

```
static ofw_def_t ofw_fdt = {
        OFW_FDT,
        ofw_fdt_methods,
        0
};
OFW_DEF(ofw_fdt);
```

c0440595-c0200000なアドレスに実態はあるように見えます。

```
% hexdump -c Pcduino_Lite_kernel | grep ^0240590
0240590   r   t   y  \n  \0   o   f   w   _   f   d   t  \0   d   t   b
```

u-bootでロードすると確かにofw_fdtの実態が空になる。なんでかな。

```
=> md 0x40236e4c 4 
40236e4c: e30175d4 e30145d0 e3a08000 e34c7046    .u...E......FpL.
=> md 0x404615d0 4 
404615d0: c04d1c4c c04d2804 c04d284c c04d2978    L.M..(M.L(M.x)M.
=> md 0x404d1c4c 4 
404d1c4c: 00000000 00000000 00000000 00000000    ................
```

kbinをロードしても同じ。

```
=> tftpboot 0x40200180 Pcduino_Lite_kernel.kbin
```

c04d1c4c(02d1c4c)にあるべきものがELFだと02d0c4cにあるようだ。ELFを理解してロードしなければちゃんと実行できないのかも。

```
% readelf -S Pcduino_Lite_kernel | grep '\.data'
  [19] .data             PROGBITS        c04c7a00 2c6a00 0324d4 00  WA  0   0 64
```

で

```
Disassembly of section .data:

c04c7a00 <esym>:
c04c7a00:       c054c000        subsgt  ip, r4, r0
```

```
% hexdump Pcduino_Lite_kernel.kbin | grep "c000 c054"
027f7e0 0104 0000 0012 0001 00a1 0000 c000 c054
028a790 01ac 0000 0012 0001 9d81 0001 c000 c054
02c6880 c000 c054 0024 0000 0000 0000 f8e9 3454
```

最後の行がそれなんだが02c6880+180で02c6a00なんでやっぱずれます。

FreeBSDでは11くらいで、objcopyを従来のbinutilsのobjcopyからBSDライセンスのelftoolchainのelfcopyに変更しました。

pkgでarm-elf-binutilsをインストールしてこちらのobjcopyを使ったら、上記の問題は解決しました。

objcopy(elfcopy)の不具合レポートMLに送っておこうと思います。

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=232922

リンカースクリプトによってELFのままでも起動できたりobjcopyしたものが起動できますが、アドレスの間違いなどがあるかもしれないので、u-bootイメージが一番問題なく起動できる気がします。

```
=> tftp 0x41000000 Pcduino_Lite_kernel.kbin.gz.uboot
=> bootm
```

initarm()のpmap_bootstrap_prepare(lastaddr)で落ちるのですが、原因がわからないのでとりあえずしばらく放置します。

armv7はメジャーなターゲットだと思うのですが、いろいろな人が手を入れて複雑になってしまって、いばらの道になってしまっているような感じがあります。

あとAllwinnerのサポートは当初A10などをターゲットにしたコードがあったようですが、次々チップが増えてそのコードを継ぎ足し継ぎ足ししたので、ちょと汚くなってる感じがします。

12.0-RC1のimageを試してみましたが、起動はしますが、途中でとまります。

```
...
Starting file system checks:
/dev/ufs/rootfs: FILE SYSTEM CLEAN; SKIPPING CHECKS
/dev/ufs/rootfs: clean, 1518467 free (75 frags, 189799 blocks, 0.0% fragmentation)
```