前回までのあらすじ
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系統入っているのが普通で、まずは世間で一般的であろう GNU の binutils のが /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
これを見ると、.text
の 00148
の部分が 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.efi は objcopy -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 で置き換えてみたが、今度は未対応のフォーマットということではねられてしまった。
今後の予定
私の力量では、この辺でお手上げである。