jirutka / efi-mkuki

EFI Unified Kernel Image Maker
MIT License
17 stars 3 forks source link

Calculate initrd section offset from kernel size #5

Open lambda-funcptr opened 1 month ago

lambda-funcptr commented 1 month ago

With kernels larger than 16Mi, it appears that the PE binary will collide the kernel and initrd segments.

This PR uses the kernel size + kernel vma offset + a buffer of 16Mi to calculate the offset required for the initrd section.

I've also bumped the minor version to signal a behavior change, but I'm open to reverting if that's not a good idea. Apologies in advance if this is undercooked, I don't have great intuition on early boot behavior, but it does seem to work.


Here's an example of a large 17Mi+ kernel.

lambda@workstation artifacts % wc -c kernel                             
17286144 kernel
[NIX] > 24-08-25 16:42:48 > [0]
objdump --section-headers uki.amd.efi.old 

uki.amd.efi.old:     file format pei-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         000073d0  0000000000003000  0000000000003000  00000400  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .reloc        0000000c  000000000000b000  000000000000b000  00007800  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00001f28  000000000000c000  000000000000c000  00007a00  2**4
                  CONTENTS, ALLOC, LOAD, DATA
  3 .dynamic      00000100  000000000000e000  000000000000e000  00009a00  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .rela         00000e58  000000000000f000  000000000000f000  00009c00  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynsym       000003a8  0000000000010000  0000000000010000  0000ac00  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .osrel        000000bc  0000000000020000  0000000000020000  0000b000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .cmdline      00000031  0000000000030000  0000000000030000  0000b200  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .linux        0107c400  0000000002000000  0000000002000000  0000b400  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .initrd       02694b26  0000000003000000  0000000003000000  01087800  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
[NIX] > 24-08-25 17:56:10 > [0]

My intuition here that .linux starting at 0x2000000 with size of 0x107c400 means it runs until 0x307c400.

However, initrd is loaded at 0x3000000, so this seems to corrupt the boot process:

BdsDxe: loading Boot0001 "UEFI QEMU HARDDISK QM00001 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)
BdsDxe: starting Boot0001 "UEFI QEMU HARDDISK QM00001 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)
!!!! X64 Exception Type - 0D(#GP - General Protection)  CPU Apic ID - 00000000 !!!!
ExceptionData - 0000000000000000
RIP  - 00000000B5E32B37, CS  - 0000000000000038, RFLAGS - 0000000000010002
RAX  - 00000000BE40CF98, RCX - 00000000BF5EC017, RDX - 000000003FFFC000
RBX  - 0000000000000000, RSP - 00000000BFEFA688, RBP - 00000000BFEFA6B0
RSI  - 00000000BF5EC018, RDI - 00000000BE40CF98
R8   - 00000000B5E32B70, R9  - 0000000000001000, R10 - 00000000BFEFA690
R11  - 0000000000000000, R12 - 0000000000000000, R13 - 00000000BEB5ADC0
R14  - 0000000000000000, R15 - 00000000BFF131E0
DS   - 0000000000000030, ES  - 0000000000000030, FS  - 0000000000000030
GS   - 0000000000000030, SS  - 0000000000000030
CR0  - 0000000080010033, CR2 - 0000000000000000, CR3 - 00000000BF801000
CR4  - 0000000000000668, CR8 - 0000000000000000
DR0  - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000
DR3  - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400
GDTR - 00000000BF5DC000 0000000000000047, LDTR - 0000000000000000
IDTR - 00000000BF241018 0000000000000FFF,   TR - 0000000000000000
FXSAVE_STATE - 00000000BFEFA2E0
!!!! Find image based on IP(0xB5E32B37) (No PDB)  (ImageBase=00000000B4DC1000, EntryPoint=00000000B5E38821) !!!!

With the patched script, I generate a nicer looking PE binary:

lambda@workstation artifacts % objdump --section-headers uki.amd.efi 

uki.amd.efi:     file format pei-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         000073d0  0000000000003000  0000000000003000  00000400  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .reloc        0000000c  000000000000b000  000000000000b000  00007800  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00001f28  000000000000c000  000000000000c000  00007a00  2**4
                  CONTENTS, ALLOC, LOAD, DATA
  3 .dynamic      00000100  000000000000e000  000000000000e000  00009a00  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .rela         00000e58  000000000000f000  000000000000f000  00009c00  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynsym       000003a8  0000000000010000  0000000000010000  0000ac00  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .osrel        000000bc  0000000000020000  0000000000020000  0000b000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .cmdline      00000031  0000000000030000  0000000000030000  0000b200  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .linux        0107c400  0000000002000000  0000000002000000  0000b400  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .initrd       02694b26  000000000407c000  000000000407c000  01087800  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
[NIX] > 24-08-25 17:56:53 > [0]
lambda@workstation artifacts % diff <(objdump --section-headers uki.amd.efi.old) <(objdump --section-headers uki.amd.efi)    
2c2
< uki.amd.efi.old:     file format pei-x86-64
---
> uki.amd.efi:     file format pei-x86-64
24c24
<   9 .initrd       02694b26  0000000003000000  0000000003000000  01087800  2**2
---
>   9 .initrd       02694b26  000000000407c000  000000000407c000  01087800  2**2
[NIX] > 24-08-25 17:59:12 > [1]

This seems to work for booting the kernel I'm building:

BdsDxe: loading Boot0001 "UEFI QEMU HARDDISK QM00001 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)
BdsDxe: starting Boot0001 "UEFI QEMU HARDDISK QM00001 " from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)
[    0.000000] Linux version 6.10.4-funcptr-gcc71765a6f93 (lambda@workstation) (gcc (GCC) 13.3.0, GNU ld (GNU Binutils) 2.42) #3 SMP PREEMPT_DYNAMIC Mon Aug 12 08:28:12 EDT 2024
lambda-funcptr commented 1 month ago

Hm, ok, my bad. Placing the initrd right behind the kernel results in corruption of initrd, I've spaced the initrd from the kernel by at minimum 16Mi + kernel size as reasonable selections of magic numbers to make this work.