LFS Kernel and Boot
This is the chapter where it boots. The fifty-package marathon leaves a complete userspace sitting on a partition — but a filesystem is not a machine. Chapter 6 installs the last load-bearing pieces (the boot scripts, the fstab, the network config, the kernel itself, the bootloader), and then commits the ultimate act: rebooting into the system you built. If it comes up, you own a Linux assembled entirely from source — every binary a product of your own compiler.
First: the configuration files
Before kernel, before GRUB — the system's identity files. Inside the chroot:
# /etc/fstab — what mounts where at boot
cat > /etc/fstab << "EOF"
# file system mount-point type options dump fsck order
/dev/sda3 / ext4 defaults 1 1
/dev/sda2 none swap pri=1 0 0
proc /proc proc nosuid,noexec,nodev 0 0
sysfs /sys sysfs nosuid,noexec,nodev 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
tmpfs /run tmpfs defaults 0 0
devtmpfs /dev devtmpfs mode=0755,nosuid 0 0
tmpfs /dev/shm tmpfs nosuid,nodev 0 0
cgroup2 /sys/fs/cgroup cgroup2 nosuid,noexec,nodev 0 0
EOF
# UEFI builders add: /dev/sda1 /boot/efi vfat ...
And the network — iproute2 + a static or dhcpcd config in /etc/sysconfig/, plus /etc/resolv.conf if DNS is static:
cat > /etc/sysconfig/ifconfig.eth0 << "EOF"
ONBOOT=yes
IFACE=eth0
SERVICE=ipv4-static
IP=192.168.1.20
GATEWAY=192.168.1.1
PREFIX=24
BROADCAST=192.168.1.255
EOF
cat > /etc/resolv.conf << "EOF"
nameserver 192.168.1.1
EOF
hostname > /etc/hostname
Plus /etc/inittab (for SysVinit — defining the runlevels and the gettys), /etc/sysconfig/clock, /etc/inputrc, /etc/shells, and the sysklogd config. The book walks each; every one is a file you've been meaning to understand — now you write them from nothing.
The kernel — configuration as authorship
cd /sources/linux-*/
make mrproper
make defconfig # a sane generic starting point
make menuconfig # YOUR hardware, YOUR choices — the real work
menuconfig is the chapter's soul: an ncurses tree of every kernel option — CPU family, filesystems, device drivers, security modules. The rules of thumb:
- Built-in
[*]vs module[M]: disk controllers and root filesystem must be built-in (a module can't load before the filesystem it lives on mounts — unless you carry an initramfs; classic LFS builds them in) - Your disk controller — SATA/AHCI (
CONFIG_ATA,SATA_AHCI), NVMe (CONFIG_BLK_DEV_NVME), or virtio (CONFIG_VIRTIO_*) for QEMU — must be in - Your filesystem —
CONFIG_EXT4_FSbuilt-in - Your network card — e1000e, virtio-net, whatever the machine has
- Devtmpfs automount —
CONFIG_DEVTMPFS_MOUNT=yso/devpopulates itself at boot - UEFI —
CONFIG_EFI+EFI_VARSif you're on it
Then compile — the longest single build of the project:
make -j$(nproc)
make modules_install
cp -iv arch/x86_64/boot/bzImage /boot/vmlinuz-<ver>-lfs-12.x
cp -iv System.map /boot/System.map-<ver>
cp -iv .config /boot/config-<ver>
install -d /usr/share/doc/linux-<ver>
cp -r Documentation/* /usr/share/doc/linux-<ver>
The three files in /boot are the kernel (bzImage), its symbol map (System.map), and the recipe it was built from (.config — keep it; every future kernel starts from it).
GRUB — the door
On BIOS/MBR:
grub-install /dev/sda
cat > /boot/grub/grub.cfg << "EOF"
set default=0
set timeout=5
insmod part_msdos # part_gpt on GPT-partitioned BIOS disks
insmod ext2
set root=(hd0,3)
menuentry "GNU/Linux, Linux <ver>-lfs" {
linux /vmlinuz-<ver>-lfs-12.x root=/dev/sda3 ro
}
EOF
On UEFI/GPT: grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=LFS and the ESP mounted at /boot/efi — root=/dev/sda3 unchanged. GRUB's (hd0,3) partition numbering starts at 1; root= is the kernel's view. Getting these two right — and matching them — is the chapter's most classic mistake.
The kernel config — the critical set
The options that decide whether it boots:
# make menuconfig — the load-bearing options:
CONFIG_EXT4_FS=y # root filesystem — BUILT-IN not module
CONFIG_ATA + SATA_AHCI=y # SATA disks — or:
CONFIG_BLK_DEV_NVME=y # NVMe — or:
CONFIG_VIRTIO_BLK/PCI=y # QEMU virtio — VM builds
CONFIG_DEVTMPFS=y + DEVTMPFS_MOUNT=y # /dev populates itself at boot
CONFIG_VT=y + VT_CONSOLE=y # the virtual console — or nothing displays
CONFIG_EFI=y + EFI_VARS=y # UEFI builds
CONFIG_NET + your NIC driver=y # networking
CONFIG_TMPFS=y # /run, /dev/shm
CONFIG_PROC_FS + SYSFS=y # /proc /sys — the kernel interfaces
CONFIG_UNIX=y # unix sockets — EVERYTHING needs this
CONFIG_BINFMT_ELF=y # run ELF binaries — or nothing runs
The pattern: boot-critical = built-in [*], everything else = module [M] or off [ ]. A module can't load from a filesystem that isn't mounted — disk + rootfs + console must be built-in, or you carry an initramfs to load them early. LFS's classic path: build them in, no initramfs — simpler.
The fstab in full
cat > /etc/fstab << "EOF"
# device mount type options dump pass
/dev/sda3 / ext4 defaults 1 1
/dev/sda2 none swap pri=1 0 0
proc /proc proc nosuid,noexec,nodev 0 0
sysfs /sys sysfs nosuid,noexec,nodev 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
tmpfs /run tmpfs defaults 0 0
devtmpfs /dev devtmpfs mode=0755,nosuid 0 0
tmpfs /dev/shm tmpfs nosuid,nodev 0 0
cgroup2 /sys/fs/cgroup cgroup2 nosuid,noexec,nodev 0 0
EOF
# UEFI adds: /dev/sda1 /boot/efi vfat defaults 0 2
The dump/pass columns: pass 1 = fsck checks root first, 2 = after, 0 = never. The virtual filesystems mount nosuid,nodev,noexec — kernel interfaces shouldn't run code.
The network's files
cat > /etc/sysconfig/ifconfig.eth0 << "EOF"
ONBOOT=yes
IFACE=eth0
SERVICE=ipv4-static
IP=192.168.1.20
GATEWAY=192.168.1.1
PREFIX=24
BROADCAST=192.168.1.255
EOF
cat > /etc/resolv.conf << "EOF"
nameserver 192.168.1.1
EOF
echo "lfs" > /etc/hostname
cat > /etc/hosts << "EOF"
127.0.0.1 localhost lfs
::1 localhost
EOF
GRUB — both paths
BIOS/MBR:
grub-install /dev/sda # writes to the boot sector — the disk, not a partition
cat > /boot/grub/grub.cfg << "EOF"
set default=0
set timeout=5
insmod part_msdos # or part_gpt for GPT
insmod ext2
set root=(hd0,3) # GRUB numbering: disks 0-based, partitions 1-based
menuentry "GNU/Linux, Linux 6.x-lfs" {
linux /vmlinuz-6.x-lfs root=/dev/sda3 ro
}
EOF
UEFI/GPT:
mkfs.vfat /dev/sda1 # the ESP — if not already
mount /dev/sda1 /boot/efi # mount the ESP
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=LFS
# grub.cfg identical — GRUB-EFI reads it the same
The two numbering traps: GRUB's (hd0,3) is disk 0, partition 3 (0-indexed disks, 1-indexed partitions); the kernel's root=/dev/sda3 is Linux naming. They must match — same partition, two languages.
The boot's transcript — reading it
A successful first boot scrolls: GRUB's menu → Loading Linux 6.x → Loading initial ramdisk (or none — LFS classic has none) → kernel decompress → the device-detection flood → Freeing unused kernel memory → Run /sbin/init as init process → the init scripts' [ OK ]-style output → login:. Each stage's failure signature is the troubleshooting table's input.
The moment of truth
# exit the chroot, unmount the virtual filesystems
exit
umount -v $LFS/dev/pts
umount -v $LFS/{sys,proc,run,dev}
umount -v $LFS
reboot
Boot. GRUB's menu appears; the kernel decompresses; init starts; login prompts on a console. login: root — into a system where every single file is something you compiled. uname -a, cat /etc/lfs-release, ls / — a filesystem of your own making.
The inittab — SysVinit's boot map
cat > /etc/inittab << "EOF"
id:3:initdefault: # default runlevel — multiuser text
si::sysinit:/etc/rc.d/init.d/rc S sysinit # system init
l0:0:wait:/etc/rc.d/init.d/rc 0 # halt
l1:S1:wait:/etc/rc.d/init.d/rc 1 # single-user
l2:2:wait:/etc/rc.d/init.d/rc 2
l3:3:wait:/etc/rc.d/init.d/rc 3 # multiuser — the default
l4:4:wait:/etc/rc.d/init.d/rc 4 # X11
l5:5:wait:/etc/rc.d/init.d/rc 5
l6:6:wait:/etc/rc.d/init.d/rc 6 # reboot
ca::ctrlaltdel:/sbin/shutdown -t5 -r now # Ctrl-Alt-Del
# the gettys — the login prompts, one per virtual console:
1:2345:respawn:/sbin/agetty --noclear tty1 9600
2:2345:respawn:/sbin/agetty tty2 9600
3:2345:respawn:/sbin/agetty tty3 9600
4:2345:respawn:/sbin/agetty tty4 9600
5:2345:respawn:/sbin/agetty tty5 9600
6:2345:respawn:/sbin/agetty tty6 9600
su:S06:once:/sbin/sulogin # single-user mode prompt
EOF
Each line is id:runlevels:action:command — initdefault picks runlevel 3, sysinit runs the system-init script first, respawn restarts gettys forever (so a logged-out console re-prompts), ctrlaltdel handles the three-finger salute. telinit 1 drops to single-user; telinit 6 reboots.
The bootscripts — the rc chain
/etc/rc.d/init.d/ holds the service scripts — rc runs them per runlevel through rc.d/rcS.d/, rc.d/rc3.d/ etc. (S = start links, K = kill). The LFS book ships lfs-bootscripts — a minimal set: checkfs (fsck on boot), cleanfs, modules (load kernel modules), mountvirt (the virtual filesystems), network, sysklogd, sendsignals, reboot, halt. Each is a readable shell script — the SysV virtue: cat shows the entire boot plan.
What almost always goes wrong — and what to do
| Symptom | Cause |
|---|---|
| Kernel panic: "unable to mount root fs" | Disk controller or ext4 built as module not built-in — rebuild kernel with [*] |
| GRUB can't find the kernel | set root=(hd0,N) numbering vs actual partition — enumerate with ls at GRUB's command line |
| Boots but no network | NIC driver missing — make menuconfig, add it built-in |
| Boots but no console/keyboard | CONFIG_VT, keyboard driver missing |
/dev empty at boot | DEVTMPFS_MOUNT off — rebuild |
| GRUB error: no such partition | GPT vs MBR mismatch — insmod part_gpt or wrong root |
| Boots into GRUB rescue only | grub-install targeted the wrong disk |
| Everything works except the hostname | /etc/hostname or hosts file |
The recovery move you'll need
If it won't boot: boot the host/live system again, mount /dev/sda3 /mnt/lfs, re-mount the virtual filesystems, chroot back in — the whole chapter-4 pivot — fix the kernel config or grub.cfg, and reboot again. LFS's greatest lesson: nothing is unrecoverable while the host still boots. The chroot door works both directions.
What you now own
A Linux where ls /usr/bin is a list of things you built — where gcc --version reports a compiler you compiled, where the kernel's .config is your hardware autographed. The system is minimal — no X, no package manager, no convenience — but it's complete: it boots, logs in, runs jobs, and can compile more of itself.
Exercises
- Boot it. (The only exercise that matters.)
- Read your kernel's
.config— find the five options that would have prevented boot had they been modules. - Rebuild the kernel with one deliberate break (e.g. ext4 as
M) — watch the panic, then chroot-rescue it back. - Write the fstab from memory; compare to the book's.
df -h /— how big is the system you built?
Timeline
| Step | Result |
|---|---|
| Config files | fstab, inittab, network, hostname |
| Kernel config | Your hardware, autographed into .config |
| Kernel build | bzImage + System.map + .config in /boot |
| GRUB | The bootloader installed and written |
| Reboot | The machine runs itself |
| next | BLFS — X, tools, the usable system beyond the base |
References
- linuxfromscratch.org — chapters 9–10: system configuration, kernel, bootloader
- The kernel's own Kconfig documentation —
make menuconfig's reference - GRUB manual — boot-time partition/device naming