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