Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initramfs specified by INITRD= not found by Linux #52

Open
synackd opened this issue Oct 31, 2021 · 7 comments
Open

Initramfs specified by INITRD= not found by Linux #52

synackd opened this issue Oct 31, 2021 · 7 comments

Comments

@synackd
Copy link
Contributor

synackd commented Oct 31, 2021

When testing with the QEMU board, Linux seems to be unable to find the initramfs passed via INITRD=in the make command, only seeming to work when the initramfs is compiled into the kernel via CONFIG_INITRAMFS_SOURCE.

For instance, when building the QEMU board with Linux 4.14.62 and the following make command:

make BOARD=qemu KERNEL=bzImage INITRD=initramfs.cpio.xz

...the following is the trimmed output of Linux:

[...]
[    1.126287] VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
[    1.131970] Please append a correct "root=" boot option; here are the available partitions:
[    1.137506] 0100           65536 ram0 
[    1.137542]  (driver?)
[    1.148742] 0101           65536 ram1 
[    1.148757]  (driver?)
[    1.157381] 0102           65536 ram2 
[    1.157392]  (driver?)
[    1.166110] 0103           65536 ram3 
[    1.166121]  (driver?)
[    1.174361] 0104           65536 ram4 
[    1.174371]  (driver?)
[    1.183369] 0105           65536 ram5 
[    1.183379]  (driver?)
[    1.191239] 0106           65536 ram6 
[    1.191248]  (driver?)
[    1.199519] 0107           65536 ram7 
[    1.199532]  (driver?)
[    1.206887] 0108           65536 ram8 
[    1.206897]  (driver?)
[    1.215189] 0109           65536 ram9 
[    1.215201]  (driver?)
[    1.222033] 010a           65536 ram10 
[    1.222042]  (driver?)
[    1.230619] 010b           65536 ram11 
[    1.230639]  (driver?)
[    1.238051] 010c           65536 ram12 
[    1.238061]  (driver?)
[    1.246527] 010d           65536 ram13 
[    1.246538]  (driver?)
[    1.252880] 010e           65536 ram14 
[    1.252890]  (driver?)
[    1.259175] 010f           65536 ram15 
[    1.259203]  (driver?)
[    1.266338] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[    1.269803] Kernel Offset: disabled
[    1.273164] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

The kernel cannot find the initramfs.cpio.xz, even though it is included in the linuxboot.rom.

EDIT: Clarified that INITRD= is a build parameter, not a kernel parameter.

@synackd
Copy link
Contributor Author

synackd commented Oct 31, 2021

I suspected it might have something to do with telling the kernel where the initramfs is loaded here in dxe/linuxboot.c:

               uintptr_t hdr = (uintptr_t) loaded_image->ImageBase;
               *(uint32_t*)(hdr + 0x218) = (uint32_t)(uintptr_t) initrd_buffer;
               *(uint32_t*)(hdr + 0x21c) = (uint32_t)(uintptr_t) initrd_length;

I tried replacing this block with struct names as specified in https://www.kernel.org/doc/Documentation/x86/boot.txt:

               struct boot_params * base = (struct boot_params*) loaded_image->ImageBase;
               base->hdr.ramdisk_image = (uint32_t)(uintptr_t) initrd_buffer;
               base->hdr.ramdisk_size  = (uint32_t)(uintptr_t) initrd_length;

but that had no effect.

@tlaurion
Copy link

@rminnich?

@rminnich
Copy link
Collaborator

rminnich commented Nov 5, 2021

if you need to point to where the kernel is in memory, use the initrdmem option. No need to hack code.

@synackd
Copy link
Contributor Author

synackd commented Nov 5, 2021

What about kernels before 5.8 (I'm using 4.14.62)? The Linuxboot DXE is already loading the initramfs and pointing the kernel header to it (the code block I referenced) like a bootloader (e.g. GRUB) would. I assume this worked before?

Perhaps the other obligatory fields mentioned in Documentation/x86/boot.txt need to be set as well.

@synackd
Copy link
Contributor Author

synackd commented Nov 5, 2021

@rminnich Sorry, I realize that my initial comment was ambiguous and I have reworded it. I'm specifying INITRD= as an argument to make, not as a kernel parameter.

@synackd
Copy link
Contributor Author

synackd commented Dec 3, 2021

Looks like the kernel still needs the EFI_BDS patch so that boot_params->hdr.ramdisk_image doesn't get overwritten to NULL.

For 4.14.62:

diff -u --recursive ../../clean/linux-4.14.62/arch/x86/boot/compressed/eboot.c linux-4.14.62/arch/x86/boot/compressed/eboot.c
--- ../../clean/linux-4.14.62/arch/x86/boot/compressed/eboot.c  2018-08-09 06:16:40.000000000 -0400
+++ linux-4.14.62/arch/x86/boot/compressed/eboot.c      2018-08-09 10:13:11.801000000 -0400
@@ -630,8 +630,8 @@
        u16 *s2;
        u8 *s1;
        int i;
-       unsigned long ramdisk_addr;
-       unsigned long ramdisk_size;
+       unsigned long ramdisk_addr = 0;
+       unsigned long ramdisk_size = 0;
 
        efi_early = c;
        sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
@@ -686,9 +686,6 @@
        /* Fill in upper bits of command line address, NOP on 32 bit  */
        boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
 
-       hdr->ramdisk_image = 0;
-       hdr->ramdisk_size = 0;
-
        /* Clear APM BIOS info */        memset(bi, 0, sizeof(*bi));
 
@@ -712,10 +709,16 @@
 
        if (status != EFI_SUCCESS)
                goto fail2;
-       hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
-       hdr->ramdisk_size  = ramdisk_size & 0xffffffff;-       boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
-       boot_params->ext_ramdisk_size  = (u64)ramdisk_size >> 32;
++       // don't overwrite the bzImage or loader provided ramdisk pointer
+       // unless the kernel command line specified a different one.+       if (ramdisk_addr != 0)
+       {
+               hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
+               hdr->ramdisk_size  = ramdisk_size & 0xffffffff;
+               boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
+               boot_params->ext_ramdisk_size  = (u64)ramdisk_size >> 32;
+       }
 
        return boot_params;
 fail2

For a more contemporary kernel like 5.16-rc3:

diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index f14c4ff..d1127dc 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -411,9 +411,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
        efi_set_u64_split((unsigned long)cmdline_ptr,
                          &hdr->cmd_line_ptr, &boot_params->ext_cmd_line_ptr);
 
-       hdr->ramdisk_image = 0;
-       hdr->ramdisk_size = 0;
-
        efi_stub_entry(handle, sys_table_arg, boot_params);
        /* not reached */

@synackd
Copy link
Contributor Author

synackd commented Dec 3, 2021

Perhaps Linuxboot could support the newer EFI stub v1.0 which finds and load the initrd which is exposed via the LoadFile2 protocol?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants