Slide 1

Slide 1 text

Blend XMODEM UEFI de XMODEM 2017/11/18 KernelVM@Kansai8

Slide 2

Slide 2 text

$ who @tnishinaga

Slide 3

Slide 3 text

今回の話 AARCH64ボードのUEFI上でXMODEMを動かします

Slide 4

Slide 4 text

今回の話 AARCH64ボードのUEFI上でXMODEMを動かします

Slide 5

Slide 5 text

今回の話 AARCH64ボードから 発表がておくれるほどに受けた 数々のご褒美(?)についてのお話

Slide 6

Slide 6 text

そもそもの動機 1. AARCH64の勉強がしたい a. UEFIから起動するOSもどきを作ってみたい 2. 手元にあるHiKey Boardでやりたい 3. 毎回SDカード抜き差しするの大変 4. リモートからプログラムを送りたい

Slide 7

Slide 7 text

リモートからプログラムを 送りたい!

Slide 8

Slide 8 text

リモートからプログラムを送る方法たち ● シリアル転送(X/Y/Z MODEM, Kermit) ○ メリット:追加部品がいらない。パソコン側の設定もいらなくて楽。 ○ デメリット:遅い。実装が面倒。 ● ネットワークブート(PXE(TFTP)ブート) ○ メリット: 速い。安心(UEFI側の実装がちゃんとしてれば)。 ○ デメリット: USB-NIC購入(1000円くらい)が必要(Hikey boardはNICを持たない)。 パソコン側の設定がちょっと必要。 ○ https://wiki.linaro.org/Boards/Hikey/Setup/TFTPBoot

Slide 9

Slide 9 text

XMODEM ● X,Y,Z MODEM中で最も単純なバイナリ転送プロトコル ● 大抵のシリアル通信アプリケーション(minicom, TeraTerm)か ら使える ● 一部、効率や機能が不十分 ○ でも今回のようにプログラムを送りつけるだけなら問題なし

Slide 10

Slide 10 text

XMODEMの通信フロー ● 送信側が受信側からNAKを受 け取ると通信開始 ● 送信側がデータを送信、受信側 がACKを返して1ブロックずつ転 送 ● 送信側がEOTを送ると受信側 はACKを返して転送終了 Receiver Sender Block data 1 ACK Block data 2 NAK NAK EOT ACK

Slide 11

Slide 11 text

XMODEMのエラー通信フロー ● 受信ブロックが壊れている場合 はNAK(再送要求)を送る ● 送信側はNAKを受け取ると、前 回のブロックを再送する ● 再度受け取ったブロックが正常 ならACKを返して通信再開 ● 送信側は一定回数以上NAKを 受け取ると通信を諦める Receiver Sender Block data 1 NAK Block data 1 NAK NAK ACK

Slide 12

Slide 12 text

ね? 簡単でしょ?

Slide 13

Slide 13 text

簡単じゃなかった

Slide 14

Slide 14 text

ご褒美1 Q. UEFIの文字コードはUTF-16。 1byte read/writeをするにはどうすれば? A. “SERIAL IO PROTOCOL”を使う

Slide 15

Slide 15 text

SERIAL IO PROTOCOL ● ボードのシリアルポートを直接Read/Writeできる ○ http://wiki.phoenix.com/wiki/index.php/EFI_SERIAL_IO_PROTOCOL ● 使い方 ○ LocateHandleでSERIAL_IO_PROTOCOLのハンドラを取得 ■ シリアルポートが複数ある場合、各ポートに対応した複数のハンドラが取得できる ○ HandleProtocolで任意のハンドラからSERIAL_IO_PROTOCOLを取得 ○ SERIAL_IO_PROTOCOLのRead/Writeを使って読み書きすればOK ■ https://github.com/tnishinaga/baremetal_hikeyboard/blob/master/uefi_serial_echo_sampl e/main.c

Slide 16

Slide 16 text

ご褒美2 Q. どうやって一定時間ごとに 受信待ちループを解除してNAK送信するの? (UEFIアプリは割り込み処理が大変) (受信側スタート厳しくない?) A. SERIAL_IO_PROTOCOLのSetAttibutesで タイムアウトを設定する

Slide 17

Slide 17 text

SetAttributes ● タイムアウト設定できる ○ 0にするとデフォルト ● NAK送信→受信待ち→タイム アウト→NAK送信→... とすれば行ける!! http://wiki.phoenix.com/wiki/index.php/EFI_SERIAL_I O_PROTOCOL#SetAttributes.28.29

Slide 18

Slide 18 text

うまく動かない デバッグしないと

Slide 19

Slide 19 text

ご褒美3 Q. シリアル1本XMODEMで使ってるよね? どこでPrintf debugするの? A. シリアルを2本生やせば良いのでは?

Slide 20

Slide 20 text

シリアルを2本生やす ● QEMUならオプションでUSBやPCIバスにシリアルデバイスを 生やせる......? ○ qemu-system-aarch64 FOOBAR \ -chardev pty,id=pts0 -device isa-serial,chardev=pts0 -chardev pty,id=pts1 -device isa-serial,chardev=pts1

Slide 21

Slide 21 text

生えない

Slide 22

Slide 22 text

シリアルが2本生えない ● AARCH64はisa-busに繋げない ● USB, PCIにはつなげるが、UEFI側が認識しない ● QEMUのコードを読むとVirtマシン*には元々1本しかシリアル ポートがマッピングされていない(?) ○ https://github.com/qemu/qemu/blob/master/hw/arm/virt.c *: Linaroの出してるQEMUようUEFIイメージはVirtマシン専用

Slide 23

Slide 23 text

ご褒美4 Q. どうやってシリアルを2本生やすの? A. x86_64のQEMUに生やす

Slide 24

Slide 24 text

x86 QEMUでシリアルを2本生やす ● x86_64のQRMUならシリアルを2本生やせる ○ qemu-system-x86_64 -cpu qemu64 \ -drive if=pflash,format=raw,unit=0,file=/usr/share/ovmf/ovmf_code_x64.bin,readonly=on \ -drive if=pflash,format=raw,unit=1,file=/usr/share/ovmf/ovmf_vars_x64.bin \ -hda fat:rw:. \ -chardev pty,id=pts0 -device isa-serial,chardev=pts0 \ -chardev pty,id=pts1 -device isa-serial,chardev=pts1 ● ちゃんとUEFI側でも認識する ○ 片方をデバッグ、片方をXMODEM通信用にしてデバッグ開始

Slide 25

Slide 25 text

MINICOM vs TMUX

Slide 26

Slide 26 text

ご褒美5 ● ptsをめぐる争い a. QEMUがシリアルポートをptsにつなげる b. minicomでptsを開く c. QEMUを終了する(minicomはptsを開いたまま) d. tmuxで新しいウィンドウを開く e. tmuxとminicomの入出力が繋がり入力を奪い合う ● 対応 a. デバッグ中は今開いてるターミナルだけで頑張る

Slide 27

Slide 27 text

データの一部 消えてない?

Slide 28

Slide 28 text

ご褒美6 ● 問題 a. 送信側はNAKを受け取ってデータを送ろうとしてる b. 受信側はデータを受け取れずタイムアウトしてNAKを送る c. NAKを受け取った送信側はデータを再送する d. 以降繰り返し e. (データが闇に消えてる気がする) ● 対策 a. タイムアウトを数回繰り返すまで待ってからNAKを送るようにした b. ちょっとぎこちないがx86のQEMU上ではデータを受け取れた

Slide 29

Slide 29 text

後は実機に持っていくだけ!

Slide 30

Slide 30 text

動かない。

Slide 31

Slide 31 text

ご褒美7 ● 問題 a. ご褒美6と同じく、データを受け取れずNAKを送り続けている b. デバッグしたいがシリアル1本しか無い ● 対策 a. ファイルに書き出せば良いのでは?

Slide 32

Slide 32 text

UEFIでのファイル読み書き 1. HandleProtocolとmainの引数のimage handleから LOADED_IMAGE_PROTOCOLを取得する 2. 再度HandleProtocolとLOADED_IMAGE_PROTOCOLのDeviceHandleからボ リュームのEFI_FILE_IO_INTERFACEを取得する 3. EFI_FILE_IO_INTERFACEのOpenVolumeでストレージのルートを開いた EFI_FILE_PROTOCOLを得る 4. EFI_FILE_PROTOCOLのOpenでファイルを開く 5. EFI_FILE_PROTOCOLのWriteでファイルに書き込む 6. EFI_FILE_PROTOCOLのCloseでファイルを閉じる

Slide 33

Slide 33 text

これでログが取れるね!

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

書き込みデータがお かしい

Slide 36

Slide 36 text

ご褒美8 ● 問題 ○ 書き込んだ文字列が謎のデータに化けてる ○ 実機だけ発生。QEMUでは発生しない。 ● 対策 ○ 実機のファームウェアをアップデートしてみよう

Slide 37

Slide 37 text

HiKey boardをアップデートしよう ● HiKey BoardのUEFIファーム導入方法は以下参照 ○ https://github.com/96boards/documentation/wiki/HiKeyUEFI

Slide 38

Slide 38 text

ご褒美9 Q. 同じようなファイルのダウンロード先 が複数(Debian, Android, release, snapshot...) あるけど何処のをつかえばいいの? A. UEFI Shellを使いたいなら uefi-openplatformpkgのlatestをつかえば良い (reference-platformのはちょい使いづらい)

Slide 39

Slide 39 text

HiKey boardをアップデートしよう ● openplatformpkgなどからファイルを取得する ○ wget https://builds.96boards.org/snapshots/reference-platform/components/uefi-staging/latest/hikey/release/hisi-i dt.py ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/l-loader.bin ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/fip.bin ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/ptable-linux-4g.img ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/ptable-linux-8g.img ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/nvme.img ● boot-fat.uefi.imgは空のFATパーティションを用意する ○ 既にBOOTパーティションにGRUB等が書き込まれている場合はShellが正しく 起動しなくなる ■ dd if=/dev/zero of=boot-fat.uefi.img bs=1M count=64 && mkfs.vfat boot-fat.uefi.img

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

HiKey boardをアップデートしよう ● openplatformpkgなどからファイルを取得する ○ wget https://builds.96boards.org/snapshots/reference-platform/components/uefi-staging/latest/hikey/release/hisi-i dt.py ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/l-loader.bin ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/fip.bin ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/ptable-linux-4g.img ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/ptable-linux-8g.img ○ wget https://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/nvme.img ● boot-fat.uefi.imgは空のFATパーティションを用意する ○ 既にBOOTパーティションにGRUB等が書き込まれている場合はShellが正しく 起動しなくなる ■ dd if=/dev/zero of=boot-fat.uefi.img bs=1M count=64 && mkfs.vfat boot-fat.uefi.img

Slide 42

Slide 42 text

HiKey boardをアップデートしよう ● その後 ○ ドキュメントを参照しながらファームを更新する ■ https://github.com/96boards/documentation/wiki/HiKeyUEFI ○ UEFI Shellを使いたいだけならboot-fat.uefi.img の書き込みまでで止めて良 い

Slide 43

Slide 43 text

正しく 書き込めるようになった

Slide 44

Slide 44 text

これでログが取れるね!

Slide 45

Slide 45 text

時間切れ

Slide 46

Slide 46 text

まとめ ● XMODEMはプロトコルは簡単だがUEFIでの実装結構大変 ● UEFIではSERIAL_IO_PROTOCOLを使うと バイト単位でシリアル読み書きできる ● SERIAL_IO_PROTOCOLでタイムアウト使ったときの 受信データの扱いは不安 ● ptsはtmux等との奪い合いが起こる。仲良くしてほしい。 ● UEFIでシリアルを使うアプリのデバッグ大変 ● 実機のUEFI実装にはバグがあるかも。 エミュレータでの動作と比較検証大事。