You are not logged in.

#1 2017-03-12 19:08:42

SysGhost
Member
From: Stockholm
Registered: 2012-11-09
Posts: 62

Loading the kernel directly on EFI systems. My approach...

Since I only run Arch on my laptop, I thought: Why even use a loader? The linux kernel that Arch is providing have the EFISTUB compiled in.
So I searched around a little, and came up with my own approach on the matter. Perhaps there are already scripts/tools for this, but none that I could find. Probably it exist under a package name that makes no what so ever sense to anyone.

Anyway, here's how I did it:


Most UEFI systems can only load up firmware packages from $ESP\EFI\<some_folder>\<fw-package>.efi
The kernel package "linux", installs the kernel image to /boot/vmlinuz-linux, so we need to copy or move the kernel to a proper ESP path.
First I mounted up the ESP partition to /boot, which is the way most people would do it.

# mount /dev/sda1 /boot

Copy the kernel to /boot/EFI/Arch/vmlinuz-linux.efi. the .efi extension is needed for the UEFI firmware to recognise it as a loadable firmware package, which the kernel happens to be thanks to the EFISTUB part compiled in by default.

# mkdir /boot/EFI/Arch
# cp /boot/vmlinuz-linux /boot/EFI/Arch/vmlinuz-linux.efi


Now that we have the kernel image on the right path, we also need to add it to the efi system. But the trick here is that one can't just add the kernel "as-is" like one would do with any other EFI firmware package. The kernel also needs command line options in order to be able to boot the rest of the system properly. In my case these options are:

initrd=\initramfs-linux.img root=PARTLABEL=Root rw quiet splash

I'm not going to guide you through all the options. I assume you already know what they do, and what you need in your case. Instead of PARTLABEL, one can use PARTUUID, or even just UUID. It all depends on your needs.

In order to add the kernel and the command line options, I used efibootmgr. Install that package if needed.

echo "initrd=\initramfs-linux.img root=PARTLABEL=Root rw quiet" | iconv -f ascii -t ucs2 | efibootmgr --create --disk /dev/sda --part 1 --label "Arch" --loader '\efi\arch\vmlinuz-linux.efi' --append-binary-args -

Explanation: I need the kernel command line string to be in pure ascii (some shells use UTF16/unicode format, which will confuse the UEFI system). Also I need convert it to a  binary format. That's why I echo the string through  "iconv -f ascii -t ucs2". efibootmgr then reads that binary string from stdin, and the option --append-binary-args is the magic here.

A quick check reveals that it has been added into the efi boot order:

BootCurrent: 0000
Timeout: 0 seconds
BootOrder: 0000,0001,2001,2002,2003
Boot0000* Arch      HD(1,GPT,d48748bc-8c1b-4c2a-9ef8-b3ec10595073,0x800,0x100000)/File(\efi\arch\vmlinuz-linux-zen.efi)i.n.i.t.r.d.=.\.i.n.i.t.r.a.m.f.s.-.l.i.n.u.x.-.z.e.n...i.m.g. .r.o.o.t.=.P.A.R.T.L.A.B.E.L.=.R.o.o.t. .r.w. .q.u.i.e.t. .s.p.l.a.s.h.
Boot0001* EFI HDD Device (KINGSTON SM2280S3G2240G)      PciRoot(0x0)/Pci(0x1f,0x2)/Sata(1,0,0)/HD(1,GPT,d48748bc-8c1b-4c2a-9ef8-b3ec10595073,0x800,0x100000)RC
Boot2001* EFI USB Device        RC
Boot2002* EFI DVD/CDROM RC
Boot2003* EFI Network   RC

Reboot and test it. If the "BootCurrent" shows the same ID as the one that has the given label, it worked. "Arch" in this case.
Congratulations. You've done it.



It is quite cumbersome to do every time the kernel updates. I guess this is why most people just skipped out on it. Too much hassle for a minimal gain.
Let's automate it!



We have something called "alpm-hooks". In other words, hooks that triggers when pacman installs/updates packages. We can create a simple hook that triggers each time the kernel is updated by pacman.
First off we need a simple script that is easy to maintain. Same it to /usr/local/bin/efibootentryupdate.sh

#!/bin/sh
LABEL="Arch Zen"
BOOT_OPTIONS="root=PARTLABEL=Root rw quiet splash"
BOOT_KERNEL="vmlinuz-linux-zen"
BOOT_IMAGES="initramfs-linux-zen.img"   # Multiple images can be given separated with a space.
BOOT_DISK="/dev/sdb"
ESP_PARTITION="1"   # Which partition number is the ESP partition?
EFI_SUB_PATH="Arch"



_EFIENTRY=$(efibootmgr | grep "$LABEL")
EFIENTRY="${_EFIENTRY:4:4}"

if [ -z "$EFIENTRY" ]
then
  echo "No boot entry labeled $LABEL found. Aborting."
  exit
fi

for BOOT_IMAGE in $BOOT_IMAGES
do
 INITRD="${INITRD}initrd=\\$BOOT_IMAGE "
done

cp -f /boot/$BOOT_KERNEL /boot/EFI/$EFI_SUB_PATH/$BOOT_KERNEL.efi
efibootmgr -q -b $EFIENTRY -B 
echo "$INITRD $BOOT_OPTIONS" | iconv -f ascii -t ucs2 | efibootmgr --quiet --create --disk $BOOT_DISK --part $ESP_PARTITION --label "$LABEL" --loader '\efi\arch\'$BOOT_KERNEL'.efi' --append-binary-args -

There. It'll keep your EFI/ESP updated whenever the kernel is updated. It will also include the given command line options.
If you ever need to change the command line options, simply edit /usr/local/bin/efibootentryupdate.sh, and then run it as root.



Final words:
The examples are far from perfect, and can be improved upon a lot. If you have ideas, examples and better ways to do things, please do tell. It is the sole reason to why I'm creating this thread. Let us improve this.
EDIT: Made some improvement on the efibootentry update script. Also to clarify: I have the hook running the script instead of the simple cp command to be more flexible with various kernels. This way one barely have to touch the hook file, or any other files, if at all. Everything can be maintained within the one script.
I do modify the cmdline every now and then, and also happen to try various kernels out, so instead or rerunning two commands, whereas one is kinda long and cumbersome to remember, I put it into one script.

Last edited by SysGhost (2017-03-12 21:33:33)

Offline

#2 2017-03-12 19:14:41

Head_on_a_Stick
Member
From: London
Registered: 2014-02-20
Posts: 7,732
Website

Re: Loading the kernel directly on EFI systems. My approach...

SysGhost wrote:

If you have ideas, examples and better ways to do things, please do tell.

https://wiki.archlinux.org/index.php/EFISTUB#efibootmgr

The installation guide recommends mounting /boot to the ESP anyway so no hooks are needed with that method wink

Offline

#3 2017-03-12 19:34:18

Scimmia
Fellow
Registered: 2012-09-01
Posts: 11,544

Re: Loading the kernel directly on EFI systems. My approach...

As discussed on IRC, the vast majority of this is useless. If you want to directly use the stub loader, you make the boot entry with efibootmgr, and you make a simple hook that copies the kernel if you really need it (firmware dependent). The rest of this is cruft.

Last edited by Scimmia (2017-03-12 19:34:47)

Offline

#4 2017-03-12 19:44:21

SysGhost
Member
From: Stockholm
Registered: 2012-11-09
Posts: 62

Re: Loading the kernel directly on EFI systems. My approach...

Scimmia wrote:

As discussed on IRC, the vast majority of this is useless. If you want to directly use the stub loader, you make the boot entry with efibootmgr, and you make a simple hook that copies the kernel if you really need it (firmware dependent). The rest of this is cruft.

I think that there might be some way that is easy to update the cmdline if needed. I can agree upon that running the efibootmgr each update might be a bit of overdoing it.
I'll make some adjustments.

The idea is to be able to edit a simple file in order to update the cmdline, instead of memorising and running a rather long command.
And if one is to run another kernel, say for instance, the zen version, it is easier to edit the scripts variables.
Kernel maintenance boils down to updating one script, instead of various files spread around.

Why not systemd-boot?
The goal is to skip all loaders. In my case, my lenovo laptop adds an odd 3 second delay on systemd-boot. It's faster loading the kernel directly, and I wanted it to be rather easy to maintain by having one script to edit no matter what kernel version/variant one decides to run. Switch kernel and it's equally as easy. Without that one have to do all the changes manually. Not that it would take much anyway. but I want to keep maintenance simple, even if the approach might be initially  complicated.

Last edited by SysGhost (2017-03-12 19:50:54)

Offline

#5 2017-03-12 19:46:32

Head_on_a_Stick
Member
From: London
Registered: 2014-02-20
Posts: 7,732
Website

Re: Loading the kernel directly on EFI systems. My approach...

SysGhost wrote:

I think that there might be some way that is easy to update the cmdline if needed.

My link wrote:

Tip: Save the command for creating your boot entry in a shell script somewhere, which makes it easier to modify (when changing kernel parameters, for example).

wink

Offline

#6 2017-03-12 19:47:46

eschwartz
Fellow
Registered: 2014-08-08
Posts: 4,097

Re: Loading the kernel directly on EFI systems. My approach...

Since I only run Arch on my laptop, I thought: Why even use a loader?

The unstated aspect of this question was mentioned on IRC...

Apparently SysGhost's machine has a mysterious three-second delay when using systemd-boot. From the Wiki: "If your motherboard has a good UEFI implementation, it is possible to embed the kernel parameters within a UEFI boot entry and for the motherboard to boot Arch directly."
As noted in the OP, apparently this machine also does not have a good UEFI implementation, since it doesn't accept [ESP]/vmlinuz-linux as a valid EFI executable unless it gets moved to an arbitrarily-chosen folder hierarchy.

The real question is, is it really worth the three seconds to kludge together a really fragile pseudo-boot manager? Especially when simpler solutions exist even for that?

Last edited by eschwartz (2017-03-12 19:51:14)


Managing AUR repos The Right Way -- aurpublish (now a standalone tool)

Offline

#7 2017-03-12 19:50:13

Head_on_a_Stick
Member
From: London
Registered: 2014-02-20
Posts: 7,732
Website

Re: Loading the kernel directly on EFI systems. My approach...

Eschwartz wrote:

Apparently SysGhost's machine has a mysterious three-second delay when using systemd-boot

My firmware also suffers with that hmm

I would advise the OP to switch to GRUB instead, that bootloader does not suffer the delay on my hardware.

Offline

#8 2017-03-12 19:53:34

eschwartz
Fellow
Registered: 2014-08-08
Posts: 4,097

Re: Loading the kernel directly on EFI systems. My approach...

Head_on_a_Stick wrote:
Eschwartz wrote:

Apparently SysGhost's machine has a mysterious three-second delay when using systemd-boot

My firmware also suffers with that hmm

I would advise the OP to switch to GRUB instead, that bootloader does not suffer the delay on my hardware.

Huh... another reason grub is the superior bootloader.


Managing AUR repos The Right Way -- aurpublish (now a standalone tool)

Offline

#9 2017-03-12 21:27:49

SysGhost
Member
From: Stockholm
Registered: 2012-11-09
Posts: 62

Re: Loading the kernel directly on EFI systems. My approach...

My link wrote:

Tip: Save the command for creating your boot entry in a shell script somewhere, which makes it easier to modify (when changing kernel parameters, for example).

Well... that is exactly what I am doing here. Putting the relevant stuff in easily editable variables at the top, and the complex commands later. And making the whole thing a tad flexible towards various user needs instead one one local static need.


The goal might look like it's going towards what he boot loaders such as grub and systemd-boot already do. The key difference in my case is that it puts the kernel in as a directly loadable .efi firmware without any bloated/buggy/oddly behaving loader in between. And is easy to maintain by simply editing one single scripts variables.


Try it out and do the stuff manually, and do that while changing cmdline options and switching between kernels at the same time. You'll soon see how cumbersome the "manual method" really is.It isn't as simple as it first might appear to be.

Last edited by SysGhost (2017-03-12 21:30:35)

Offline

#10 2017-03-12 21:48:17

Head_on_a_Stick
Member
From: London
Registered: 2014-02-20
Posts: 7,732
Website

Re: Loading the kernel directly on EFI systems. My approach...

SysGhost wrote:

The goal might look like it's going towards what he boot loaders such as grub and systemd-boot already do. The key difference in my case is that it puts the kernel in as a directly loadable .efi firmware without any bloated/buggy/oddly behaving loader in between.

Well, systemd-boot is just a bootmanager rather than a bootloader and, as such, simply hands over the booting process to the (EFI_STUB enabled) kernel.

Also, with your method the weak link then becomes the bloated/buggy/oddly behaving UEFI firmware — I used pure EFI_STUB booting for quite a while but eventually switched to systemd-boot because my firmware would "loose" the custom NVRAM entries...

Offline

Board footer

Powered by FluxBB