Kernel options for an UEFI-bootable image, no initrd

From: Fabiano Sidler

Date: Sun Apr 19 2026 - 01:55:27 EST


Hi folks!

I'm trying to create an UEFI-bootable image that doesn't use an initrd.
Unfortunately, I'm only getting a black screen after this console output

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)

using the following QEMU command

qemu-system-x86_64 \
 -drive file=linux.img,format=raw \
 -bios /usr/share/qemu/OVMF.fd \
 -serial stdio

The image was created with the following script:

#!/usr/bin/zsh -e

#set -uo pipefail

image=linux.img
size_mb=512
mnt=./linuxsystem
esp=${mnt}/esp
root=${mnt}/root
linux_version=6.18.22
busybox=./busybox

mesg() {
 echo $*
}

debug() {
 echo $*
}

loopdev=""
cleanup() {
 set +e
 ( mount | grep -q "${esp}" ) && umount "${esp}"
 ( mount | grep -q "${root}" ) && umount "${root}"
 [ -n "${loopdev}" ] && losetup -d "${loopdev}"
}

trap cleanup EXIT

mesg building kernel
linux_dir=linux-${linux_version}
[ -f ${linux_dir}.tar.xz ] || wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${linux_version}.tar.xz
[ -d ${linux_dir} ] && rm -r ${linux_dir}
tar xf ${linux_dir}.tar.xz
cd ${linux_dir}
make tinyconfig
cat >> .config << HERE_I_AM
CONFIG_ATA=y
CONFIG_SATA_AHCI=y
CONFIG_BLK_DEV_NVME=y
CONFIG_VIRTIO_BLK=y
CONFIG_EXT4_FS=y
CONFIG_EFI=y
CONFIG_EFI_STUB=y
HERE_I_AM
make
cd -

mesg creating image
dd if=/dev/zero of=${image} bs=1M count=${size_mb}

mesg partitioning
parted ${image} --script \
 mklabel gpt \
 mkpart ESP fat32 1MiB 100MiB \
 set 1 esp on \
 mkpart root ext4 100MiB 100%

mesg attaching loop device
loopdev=$(losetup -Pf --show $image)

mesg formatting
mkfs.vfat -F32 ${loopdev}p1
mkfs.ext4 ${loopdev}p2

mesg mounting
mkdir -p ${esp} ${root}
mount ${loopdev}p2 ${root}
mount ${loopdev}p1 ${esp}

mesg creating minimal rootfs
mkdir -p ${root}/{{,s}bin,sbin,etc,proc,sys,usr/{,s}bin,dev}
cp ${busybox} ${root}/bin
chmod +x ${root}/bin/busybox
chroot ${root} /bin/busybox --install -s
cat > ${root}/init << 'HERE_I_AM'
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
exec /bin/sh
HERE_I_AM
chmod +x ${root}/init
root_uuid=$(blkid -s PARTUUID -o value ${loopdev}p2)
cat > ${root}/etc/fstab << HERE_I_AM
PARTUUID=${root_uuid} / ext4 defaults 0 1
HERE_I_AM

mesg installing grub
grub-install \
 --target=x86_64-efi \
 --efi-directory=${esp} \
 --boot-directory=${esp}/boot \
 --removable \
 --no-nvram

mesg installing kernel
cp linux-${linux_version}/arch/x86/boot/bzImage ${esp}/boot/vmlinuz

mesg writing grub.cfg
cat > ${esp}/boot/grub/grub.cfg << HERE_I_AM
set timeout=0
set default=0

menuentry "Linux" {
 linux /boot/vmlinuz root=PARTUUID=${root_uuid} rw console=ttyS0
}
HERE_I_AM

mesg done. image: ${image}

Am I missing some kernel options or what is the issue?

Greetings,
Fabiano