Skip to content
ALB Wiki

Diff — LFS Kernel and Boot

Comparing rev 1 → rev 2

{{infobox
| title = LFS: Kernel, Bootloader & First Boot
| chapter = Linux Handbook, chapter 6 — the system becomes a machine
| stage | LFS book chapters 9–10 — the payoff
| milestone | boot: the machine you built from source, running itself
| hardest_idea = The kernel must know your hardware before it exists as a system
| needs | The complete chroot userspace from chapter 5
| next | BLFS — building beyond the base system
}}
**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:
```sh
# /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      swap         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:
```sh
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
```sh
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_FS` built-in
- **Your network card** — e1000e, virtio-net, whatever the machine has
- **Devtmpfs automount** — `CONFIG_DEVTMPFS_MOUNT=y` so `/dev` populates itself at boot
- **UEFI** — `CONFIG_EFI` + `EFI_VARS` if you're on it
Then compile — the longest single build of the project:
```sh
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:
```sh
grub-install /dev/sda
cat > /boot/grub/grub.cfg << "EOF"
set default=0
set timeout=5
insmod part_gpt
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:
+
+
```sh
+
# 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
+
+
```sh
+
cat > /etc/fstab << "EOF"
+
# device         mount    type    options                    dump pass
+
/dev/sda3        /        ext4    defaults                   1    1
+
/dev/sda2        swap     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
+
+
```sh
+
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:**
+
+
```sh
+
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:**
+
+
```sh
+
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
```sh
# 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.
## 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
1. Boot it. (The only exercise that matters.)
2. Read your kernel's `.config` — find the five options that would have prevented boot had they been modules.
3. Rebuild the kernel with one deliberate break (e.g. ext4 as `M`) — watch the panic, then chroot-rescue it back.
4. Write the fstab from memory; compare to the book's.
5. `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
## See also
- [[LFS Preparation]] · [[LFS Cross-Toolchain]] · [[LFS Temporary System]] · [[LFS System Packages]] · [[Linux]]
[[Category:Linux]]
[[Category:LFS]]
[[Category:Handbook]]