Boot kernel from UEFI directly

5,032
   -l | --loader NAME
              Specify a loader (defaults to \\elilo.efi)

A kernel with EFI-stub is still not a loader. To boot from BIOS it has to be an EFI-application. All the boot loaders have .EFI suffix. I think it is possible to turn a kernel into such a directly bootable object, but normally it is one of the boot loaders that gets started (with or without offering a choice).

But you can use UEFI shell (on modern systems) as the interactive boot loader. This is perfect for testing. You activate it like a boot device in BIOS, cd to fs0:, which is the ESP, and then you can

fs0:> bzImage root=/dev/sda3 

I just compiled a first bzImage a few days ago. First I forgot CONFIG_EFI_STUB and the UEFI shell treated the kernel like a non-binary. A second version did boot, without any initrd=. Besides EFI_STUB=y I just switched off a few options and kept the defaults.

But it is true most distros have kernels that do not have the basic block device drivers - they need the initrd=IMAGE option.


I use Uefi Shell as my boot loader. This is not super elegant, but very simple and flexible. And as an emergency option I think it is perfect, because the Uefi Shell is built-in, while a boot loader on a partition can be deleted.


This is from Documentation/efi-stub.txt

> Passing kernel parameters from the EFI shell
> --------------------------------------------
> 
> Arguments to the kernel can be passed after bzImage.efi, e.g.::
> 
>     fs0:> bzImage.efi console=ttyS0 root=/dev/sda4

I have the same Uefi Shell prompt fs0:>, but I found that all the usual distros have EFI_STUB kernels, and the name does not matter at all. Most common is "vmlinuz" (= loader around a compressed vmlinux).

If you leave away the ".efi" and the "console=" option, this is left:

fs0:> bzImage root=/dev/sda4

Which is the same minimal boot command, except that I have sda3: Uefi Shell starts the bzImage by the stub, the kernel is unpacked and started and the built-in modules recognize the SATA disk. If the root= device is not valid, you get that VFS: unable to mount panic.


I could not manage to start a bzImage (or vmlinuz, or ...) from BIOS directly, like a grub64.EFI.


UEFI - Applications (wikipedia):

Beyond loading an OS, UEFI can run UEFI applications, which reside as files on the EFI System Partition. They can be executed from the UEFI command shell, by the firmware's boot manager, or by other UEFI applications. UEFI applications can be developed and installed independently of the system manufacturer.

A type of UEFI application is an OS loader such as GRUB, rEFInd, Gummiboot, and Windows Boot Manager; which loads an OS file into memory and executes it. Also, an OS loader can provide a user interface to allow the selection of another UEFI application to run. Utilities like the UEFI shell are also UEFI applications.

This confirms my view that the UEFI Shell is between the firmware boot loader and the kernel.


Gentoo has similar examples; they insist on naming the kernel with .EFI suffix.

If for some reason an initramfs is needed, it can either be embedded into the kernel or be used as a separate file.

...

Some UEFI implementations however seem to not support passing parameters from the NVRAM to the EFI stub kernel.

Share:
5,032
mattia.b89
Author by

mattia.b89

Updated on September 18, 2022

Comments

  • mattia.b89
    mattia.b89 almost 2 years

    I want to boot Arch Linux directly from UEFI.

    My idea is to create a boot entry using the tool efibootmgr; I used this command:

    efibootmgr --create --label "arch-test" --loader /vmlinuz-linux --unicode 'root=PARTUUID=f2083749-8bbc-570b-ab3b-e79d72fa08ac rw initrd=\initramfs-linux.img' --verbose
    

    I followed the Arch Wiki page on EFISTUB and I created the entry but when I try to boot from that, system stuck on boot at very early stage with this message:

    VFS: unable to mount root fs on unknown-block(0,0)
    

    PS: I want to have this working as emergency/rescue tool; i.e. latest systemd upgrade break up the boot manager (systemd-boot) making my machine unusable; I have been able to recover my system thanks to an external live USB. I want to AVOID this in the future!


    UPDATEs:
    1. having or not/slash or backslash, before initrd doesn't matter
    2. tried with both UUID and PARTUUID, nothing changes
    3. my /boot is on /dev/sda1 while root on /dev/sda3
    4. and /boot is ESP, as well

        # fdisk -l /dev/sda
        [...]
        Disklabel type: gpt
        [...]
    
        Device         Start       End   Sectors   Size Type
        /dev/sda1       2048   2099199   2097152     1G EFI System
        /dev/sda2    2099200  18874367  16775168     8G Linux swap
        /dev/sda3   18874368 104857599  85983232    41G Linux filesystem
        [...]
        # minfo -i /dev/sda1 :: | grep 'disk type'
        disk type="FAT32   "
    
    1. following your comments, I tried UEFI Shell. I had left this option as latest since my machine does not have an internal UEFI Shell (is it possible?). Anyway, I have:

      • downloaded one from tianocore
      • placed Shell.efi into /boot/EFI/Boot/
      • added an entry with

        efibootmgr --create --label "TIANO-0" --loader /EFI/Boot/Shell.efi --verbose
        
      • rebooted into this Shell, I typed fs0: and vmlinuz-linux root=/dev/sda3

      • resulting in the same error:

        VFS: unable to mount root fs on unknown-block(0,0)
        
    2. it looks like initrd is mandatory (at least for Arch Linux);
      the command vmlinuz-linux initrd=initramfs-linux.img root=/dev/sda3 makes the magic

    3. my system is a Dell XPS 9343 laptop and I discovered it suffers of a bug: can't boot EFISTUB, reported on ArchWiki here.
      I think it explains the failure of the (first mentioned) correct procedure!
      ArchWiki page suggests a workaround too, but at the moment I have tried it.


    • benishky
      benishky over 4 years
      You will need to build a kernel that has the drivers for the device containing the root filesystem built in.
    • mattia.b89
      mattia.b89 over 4 years
      @MurrayJensen How? Do you have some suggestions, links to guides, wikis?
    • benishky
      benishky over 4 years
      I just noticed you have a backslash () at the start of the initrd= option - try removing that ...
    • mattia.b89
      mattia.b89 over 4 years
      @MurrayJensen I tried replacing it with a normal slash, as well removing it but the result does not change
    • benishky
      benishky over 4 years
      The kernel needs drivers for the device that contains the root filesystem otherwise you will get the unable to mount error - either build them into /vmlinuz-linux or make them available as modules in /initrd-linux.img PS it needs to be a forward slash
    • mattia.b89
      mattia.b89 over 4 years
      I followed this guide [wiki.archlinux.org/index.php/Mkinitcpio] and included ext4 module as root has an ext4 partition but nothing changed;
    • benishky
      benishky over 4 years
      Maybe the partition uuid is wrong and it can't find the root filesystem?
    • mattia.b89
      mattia.b89 over 4 years
      @MurrayJensen no, try again and also with PARTUUID
    • benishky
      benishky over 4 years
      I'm out of ideas - try using the UEFI Shell and other things suggested in the EFISTUB manual ... also, looks like it does need to be backslash - it is not a linux path, it is being interpreted by UEFI, if I'm reading it right ... I should bow out here because I risk talking about things I have no experience with. Cheers!
    • muru
      muru over 4 years
      FWIW, my working command was efibootmgr --disk /dev/nvme0n1 --part 1 --create --gpt --label "Arch Linux" --loader /vmlinuz-linux --unicode "root=UUID=e5018f7e-5838-4a47-b146-fc1614673356 rw initrd=/initramfs-linux.img" (booting of the NMVe disk instead of the HDD). Where is your ESP mounted and where are the vminuz and initramfs created?
    • mattia.b89
      mattia.b89 over 4 years
      @muru /boot on /dev/sda1 while root on /dev/sda3; updated OP
    • muru
      muru over 4 years
      And is /dev/sda1 your ESP?
    • mattia.b89
      mattia.b89 over 4 years
      @muru yes, it should; I update OP with some info
  • muru
    muru over 4 years
    On Arch Linux, the kernels are EFI applications by default ("The Linux kernel supports EFISTUB booting which allows EFI firmware to load the kernel as an EFI executable. The option is enabled by default on Arch Linux kernels ..." wiki.archlinux.org/index.php/EFISTUB)
  • Admin
    Admin over 4 years
    I think EFI-stub is not EFI-application. To me it looks like Uefi Shell can execute these kernels, but BIOS can not boot into them. BIOS/efibootmgr can only boot into things like elilo.EFI, systemd-bootx64.EFI. Documentation/efi-stub.txt: "Without the extension the EFI firmware loader will refuse to execute it." is confusing, this must be from a early generation of "EFI firmware".
  • mattia.b89
    mattia.b89 over 4 years
    I tried with UEFI Shell: first, my machine doesn't have an internal one, so I downloaded one from tianocore here [github.com/tianocore/edk2/releases/tag/edk2-stable202002]; placed into my /boot/EFI/Boot; added an entry with efibootmgr; result-> I get exactly the same error; updated OP
  • Admin
    Admin over 4 years
    @mattia.b89 you left out the initrd= parameter in your EDIT5.
  • mattia.b89
    mattia.b89 over 4 years
    @muru thank you now UEFI Shell works!
  • crass
    crass over 2 years
    While it may be true to that some UEFI firmwares won't boot EFI applications without the .efi extension, that's not the case here. The firmware is clearly booting the kernel, which is why the OP gets VFS: unable to mount root fs on unknown-block(0,0), which comes from the running kernel. And the kernel with EFISTUB is an EFI application and can be a replacement for the bootloader: Since the EFI boot stub performs the jobs of a boot loader, in a certain sense it IS the boot loader. [kernel.org/doc/html/latest/admin-guide/efi-stub.html]
  • crass
    crass over 2 years
    Technically, I don't think this answers the question because the question is about booting the linux kernel directly from the UEFI environment, not UEFI shell environment. And I believe this is possible with the OP's setup, despite the UEFI firmware bug where parameters are not passed to the kernel. But it requires a custom built kernel which includes the initrd and kernel command line. With this answer, the OP is using the UEFIShell as the bootloader which could've just as easily been GRUB or another UEFI bootloader.