Pro Yearly is on sale from $80 to $50! »

Blend XMODEM -UEFI de XMODEM-/KernelvmKansai8

Blend XMODEM -UEFI de XMODEM-/KernelvmKansai8

UEFIでXMODEMを実装しようと頑張った話です。

Bdd3fb3269e67bbc512f2530c409a926?s=128

Toshifumi NISHINAGA

November 18, 2017
Tweet

Transcript

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

  2. $ who @tnishinaga

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

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

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

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

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

  8. リモートからプログラムを送る方法たち • シリアル転送(X/Y/Z MODEM, Kermit) ◦ メリット:追加部品がいらない。パソコン側の設定もいらなくて楽。 ◦ デメリット:遅い。実装が面倒。 •

    ネットワークブート(PXE(TFTP)ブート) ◦ メリット: 速い。安心(UEFI側の実装がちゃんとしてれば)。 ◦ デメリット: USB-NIC購入(1000円くらい)が必要(Hikey boardはNICを持たない)。 パソコン側の設定がちょっと必要。 ◦ https://wiki.linaro.org/Boards/Hikey/Setup/TFTPBoot
  9. XMODEM • X,Y,Z MODEM中で最も単純なバイナリ転送プロトコル • 大抵のシリアル通信アプリケーション(minicom, TeraTerm)か ら使える • 一部、効率や機能が不十分

    ◦ でも今回のようにプログラムを送りつけるだけなら問題なし
  10. XMODEMの通信フロー • 送信側が受信側からNAKを受 け取ると通信開始 • 送信側がデータを送信、受信側 がACKを返して1ブロックずつ転 送 • 送信側がEOTを送ると受信側

    はACKを返して転送終了 Receiver Sender Block data 1 ACK Block data 2 NAK NAK EOT ACK
  11. XMODEMのエラー通信フロー • 受信ブロックが壊れている場合 はNAK(再送要求)を送る • 送信側はNAKを受け取ると、前 回のブロックを再送する • 再度受け取ったブロックが正常 ならACKを返して通信再開

    • 送信側は一定回数以上NAKを 受け取ると通信を諦める Receiver Sender Block data 1 NAK Block data 1 NAK NAK ACK
  12. ね? 簡単でしょ?

  13. 簡単じゃなかった

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

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

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

    O_PROTOCOL#SetAttributes.28.29
  18. うまく動かない デバッグしないと

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

  20. シリアルを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
  21. 生えない

  22. シリアルが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マシン専用
  23. ご褒美4 Q. どうやってシリアルを2本生やすの? A. x86_64のQEMUに生やす

  24. 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通信用にしてデバッグ開始
  25. MINICOM vs TMUX

  26. ご褒美5 • ptsをめぐる争い a. QEMUがシリアルポートをptsにつなげる b. minicomでptsを開く c. QEMUを終了する(minicomはptsを開いたまま) d.

    tmuxで新しいウィンドウを開く e. tmuxとminicomの入出力が繋がり入力を奪い合う • 対応 a. デバッグ中は今開いてるターミナルだけで頑張る
  27. データの一部 消えてない?

  28. ご褒美6 • 問題 a. 送信側はNAKを受け取ってデータを送ろうとしてる b. 受信側はデータを受け取れずタイムアウトしてNAKを送る c. NAKを受け取った送信側はデータを再送する d.

    以降繰り返し e. (データが闇に消えてる気がする) • 対策 a. タイムアウトを数回繰り返すまで待ってからNAKを送るようにした b. ちょっとぎこちないがx86のQEMU上ではデータを受け取れた
  29. 後は実機に持っていくだけ!

  30. 動かない。

  31. ご褒美7 • 問題 a. ご褒美6と同じく、データを受け取れずNAKを送り続けている b. デバッグしたいがシリアル1本しか無い • 対策 a.

    ファイルに書き出せば良いのでは?
  32. 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でファイルを閉じる
  33. これでログが取れるね!

  34. None
  35. 書き込みデータがお かしい

  36. ご褒美8 • 問題 ◦ 書き込んだ文字列が謎のデータに化けてる ◦ 実機だけ発生。QEMUでは発生しない。 • 対策 ◦

    実機のファームウェアをアップデートしてみよう
  37. HiKey boardをアップデートしよう • HiKey BoardのUEFIファーム導入方法は以下参照 ◦ https://github.com/96boards/documentation/wiki/HiKeyUEFI

  38. ご褒美9 Q. 同じようなファイルのダウンロード先 が複数(Debian, Android, release, snapshot...) あるけど何処のをつかえばいいの? A. UEFI

    Shellを使いたいなら uefi-openplatformpkgのlatestをつかえば良い (reference-platformのはちょい使いづらい)
  39. 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
  40. None
  41. 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
  42. HiKey boardをアップデートしよう • その後 ◦ ドキュメントを参照しながらファームを更新する ▪ https://github.com/96boards/documentation/wiki/HiKeyUEFI ◦ UEFI

    Shellを使いたいだけならboot-fat.uefi.img の書き込みまでで止めて良 い
  43. 正しく 書き込めるようになった

  44. これでログが取れるね!

  45. 時間切れ

  46. まとめ • XMODEMはプロトコルは簡単だがUEFIでの実装結構大変 • UEFIではSERIAL_IO_PROTOCOLを使うと バイト単位でシリアル読み書きできる • SERIAL_IO_PROTOCOLでタイムアウト使ったときの 受信データの扱いは不安 •

    ptsはtmux等との奪い合いが起こる。仲良くしてほしい。 • UEFIでシリアルを使うアプリのデバッグ大変 • 実機のUEFI実装にはバグがあるかも。 エミュレータでの動作と比較検証大事。