Lenovo Yoga C630 に FreeBSD が入らない(その2)

前回までのあらすじ

FreeBSD-arm ML で Yoga C630 に FreeBSD/aarch64 がインストールできないんだけどどうしたらよかんべと聞いてみたところ、「Qualcommファームウェアefi アプリケーションが 4kb align になっていることを要求するよ」と教えてもらったが。

4kb align な loader.efi が作れない

4kb align な loader.efi ができれば勝ちなのだが、それがどうやっても作れていない。 やったことを書き連ねてみるので、こうやればいいんだというのがわかる方は教えて欲しい。

通常作られる loader.efi

make TARGET=arm64 TARGET_ARCH=aarch64 buildworld でできる loader.efi はそもそも C630 で起動しないので 4k align になっていないわけだが、それをどう確認したものか。たぶん objdump -h でヘッダ情報を見ればよいのだろうというわけで見てみる。FreeBSD をごにょごにょしていると objdump は2系統入っているのが普通で、まずは世間で一般的であろう GNUbinutils のが /usr/local/bin/objdump として入ってくる。それでヘッダ情報を見てみると、

$ /usr/local/bin/objdump -h loader_lua.efi

loader_lua.efi:     ファイル形式 msdos

セクション:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         fffffe00  00000000  00000000  00000000  2**4
                  CONTENTS, ALLOC, LOAD, CODE

となって、この Algn のところが 2**12 になればいいのかなという気がする。 しかし、この後いろいろ試すものの、ここが 2**12 になることはなかった。

さて、FreeBSD stable/13 では llvm の objdump が /usr/bin/llvm-objdump として入っている。そちらは、

/usr/bin/llvm-objdump -h loader_lua.efi

loader_lua.efi: file format coff-arm64

Sections:
Idx Name          Size     VMA              Type
  0 .reloc        00000000 0000000000000000 DATA
  1 .text         00133570 0000000000000148 TEXT

これを見ると、.text00148 の部分が 01000 になればよさそうである。 いろいろ試した結果、src/stand/efi/loader/arch/arm64/start.S の

        .section .peheader,"a"
efi_start:
        /* The MS-DOS Stub, only used to get the offset of the COFF header */
        .ascii  "MZ"
        .short  0
        .space  0x38
        .long   pe_sig - efi_start

        /* The PE32 Signature. Needs to be 8-byte aligned */
        .align  3
pe_sig:
        .ascii  "PE"
        .short  0

この部分の .align 3 のところをいじればよいことが分かった。

まず .align 3.align 12 または .balign 4096 としてみると、llvm-objdump の出力の上記の VMA の箇所は 01108 になった。GNU の objdump の出力は変わらない。そして、作成された loader_lua.efi は起動しなかった。

今度は 0x108 のぶんずらしてやろうと .align 3 に置き換えて .space 0xeb8 としてみた。 llvm-objdump の出力はちょうど 01000 になるが、GNU objdump の出力は変わらないし、作成された loader_lua.efi は起動しない。

ところで、arm64 の loader.efiobjcopy -O binary で出力されているのだけれども、 GNU objcopy のマニュアルにこんなことが書いてあって、アラインメントを整えようがないのではという疑惑が。

   objcopy can be used to generate a raw binary file by using an output
  target of binary (e.g., use -O binary).  When objcopy generates a raw
  binary file, it will essentially produce a memory dump of the contents
  of the input object file.  All symbols and relocation information will
  be discarded.  The memory dump will start at the load address of the
  lowest section copied into the output file.

ELF な loader.efi は作れるか

FreeBSD/arm64 では objcopy に指定するフォーマットを binary にして、自分で COFF ヘッダを作成している(と start.S のコメントに書いてある)のだけれども、だったら ELF にすれば 4kb align が可能ではないか。

結果的にうまくいかないので詳しくは省くが、amd64 を参考に src/stand/efi/loader/arch/arm64/ldscript.arm64 をいじれば下記のようにはなる。 ただ、これだと loader は全く BIOS に認識されずに Windows が起動してくる。 こちらについては自前で PEヘッダーを書けばよいのかもしれない。参考になる文献がないかな。

loader_lua_elf_align.efi:     ファイル形式 elf64-littleaarch64

セクション:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .eh_frame     0000004c  0000000000001000  0000000000001000  00011000  2**12
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .text         000f96f8  0000000000002000  0000000000002000  00012000  2**12
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .data         00030130  00000000000fc000  00000000000fc000  0010c000  2**12
                  CONTENTS, ALLOC, LOAD, DATA
  3 set_Xcommand_set 00000158  000000000012d000  000000000012d000  0013d000  2**12
                  CONTENTS, ALLOC, LOAD, DATA
  4 set_Xficl_compile_set 00000000  000000000012d158  000000000012d158  0013d158  2**12
                  CONTENTS, ALLOC, LOAD, DATA
  5 .sdata        00000480  000000000012e000  000000000012e000  0013e000  2**12
                  CONTENTS, ALLOC, LOAD, DATA
  6 .dynamic      000000f0  000000000012f000  000000000012f000  0013f000  2**12
                  CONTENTS, ALLOC, LOAD, DATA
  7 .dynsym       00000018  000000000013a000  000000000013a000  0014a000  2**12
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.dyn     00009828  0000000000130000  0000000000130000  00140000  2**12
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .dynstr       00000001  000000000013c000  000000000013c000  0014c000  2**12
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

grub-mkimage に頼ればいいんじゃね

grub-mkimage は 4kb align なイメージを作れているし、grub のモジュールって ELF にコンパイルした .o ぽいので、 .o を grub のモジュールだと騙してやれば grub-mkimage が loader を作ってくれるんじゃねという考えに至った。 これ自体はよい考えだと思うのだが、src/stand/efi/loader/arch/arm64/start.S で ImageBase というシンボルを参照していて、これがなんとリンク時に作成される(ldscript.arm64 を参照されたい)ので シンボルが解決できないというエラーになってしまう。 ではということで、grub の kernel.img をリンク後の loader_lua.sym で置き換えてみたが、今度は未対応のフォーマットということではねられてしまった。

今後の予定

私の力量では、この辺でお手上げである。

あきらめて Windows のまま使う? Linux を入れて使う?