Embedded Linux & Device Drivers: Kernel, Device Tree, Boot Interview Prep

Embedded Linux and device driver development explained for interviews — kernel vs user space, the driver model (character/block/network), device tree, the boot chain, cross-compilation, and Linux vs RTOS vs bare-metal.

Quick answer

Embedded Linux is the use of the Linux kernel and a tailored user-space stack on a dedicated device — a router, camera, industrial controller, infotainment unit — rather than a general-purpose computer, and device driver development is the kernel-side work of making the system's specific hardware usable.

Interviewers use embedded Linux to find engineers who understand the system from the boot ROM up, not just application programmers who happen to run on Linux.

Editorial review

Written by

CompoundLearn editorial team

Wireless / RF / hardware engineering

Reviewed by

CompoundLearn editorial team

Wireless / RF / hardware engineering

Last reviewed

Built from curated topic maps, editorial validation, and subject-matter review so the page stays aligned with the interview intent and the current content pipeline.

Key points

  • Embedded Linux is a full MMU-based OS (virtual memory, processes, networking, huge driver ecosystem) — chosen over RTOS/bare-metal when you need rich connectivity and a filesystem, not microsecond hard-real-time.
  • Kernel space (privileged, manages hardware) and user space (restricted apps) are separated; code crosses via system calls and data via copy_to_user/copy_from_user — a kernel/driver bug can crash the whole system.
  • A device tree (.dts -> .dtb) describes non-discoverable SoC hardware to the kernel at boot, decoupling one kernel image from board specifics; drivers match against compatible strings.
  • Driver classes: character (byte-stream devices, the common case for custom hardware), block (storage), network (packet interfaces); modern drivers register on a bus with probe()/remove().
  • Boot chain: ROM loader -> first-stage -> bootloader (e.g. U-Boot) -> kernel + device tree -> rootfs -> init (systemd/BusyBox). Localizing a hang means naming the failing stage.
  • You cross-compile from a host with a target toolchain (Yocto/Buildroot); debug per layer (dmesg/proc/sys/ftrace for kernel, gdbserver for user space, kgdb/JTAG for kernel).
  • Mainline Linux is not hard-real-time; PREEMPT_RT, a separate RTOS/MCU core, or a co-kernel resolve hard deadlines.

What it is

Embedded Linux is the use of the Linux kernel and a tailored user-space stack on a dedicated device — a router, camera, industrial controller, infotainment unit — rather than a general-purpose computer, and device driver development is the kernel-side work of making the system's specific hardware usable. It is distinct from generic Linux administration: the focus is the kernel, the hardware interface, and a minimal purpose-built root filesystem, on a target that is cross-compiled for and often headless. Embedded Linux makes sense when a product needs what a full OS provides — virtual memory and an MMU, a real process model, a filesystem, a networking stack, and the enormous ecosystem of existing drivers and libraries — and can afford the megabytes of RAM and storage that implies. That is the trade against an RTOS or bare metal (see /topics/rtos): you gain capability and lose the deterministic, tiny-footprint hard-real-time behavior of a microcontroller. The core concepts an embedded engineer must own are the kernel/user-space boundary and how code crosses it, the device tree that describes non-discoverable hardware to the kernel, the driver model (character, block, and network drivers, and the probe/remove lifecycle that binds a driver to a device), the boot chain from bootloader through kernel to init, and the cross-compilation and layered debugging workflow. Connecting those to the processor underneath (see /topics/arm-cortex-architecture-for-embedded) and to the broader role (see /topics/embedded-engineer-interview-signals) is what separates an embedded-Linux engineer from a Linux user.

Why interviewers ask

Interviewers use embedded Linux to find engineers who understand the system from the boot ROM up, not just application programmers who happen to run on Linux. The role sits exactly on the hardware/software boundary, so the questions probe that boundary: what a device tree is and why a non-PC SoC needs one, what happens between power-on and a shell prompt, why a driver lives in the kernel and what that costs in stability, and how you would bring up a board that produces no output. These cannot be bluffed by someone who has only written user-space code. The topic is also a judgment probe (see /topics/embedded-engineer-interview-signals). Strong candidates reason about the Linux-versus-RTOS-versus-bare-metal choice with real constraints, know that Linux is not hard-real-time and can name how to resolve a hard deadline, and debug by layer — recognizing that a driver probe failure is a dmesg-and-device-tree problem while a slow user-space task is a perf problem. Interviewers for embedded, firmware, and platform roles want to see that you can localize a failure to a boot stage or a kernel subsystem and reason about the cross-compilation and integration realities, because that systems-level fluency is what the job actually requires day to day.

Common mistakes

The most common mistake is treating embedded Linux as desktop Linux on a small box — reaching for package managers and runtime installs instead of a cross-compiled, image-based build (Yocto or Buildroot) and a minimal root filesystem. A second mistake is not understanding the device tree: candidates describe drivers but cannot explain how a driver finds its hardware on a non-enumerable SoC, or that the device tree is what binds a compatible driver to a peripheral. A third is blurring the kernel/user-space boundary — assuming a kernel module can call libc, or that a user pointer can be dereferenced directly in the kernel, rather than using the copy primitives. A fourth is assuming Linux is real-time and being surprised when deadlines slip under load, with no awareness of PREEMPT_RT or offloading to an RTOS core. A fifth is debugging without layering — reaching for gdb on a driver probe failure that dmesg would have explained, or ignoring /proc and /sys. Finally, candidates often cannot describe the boot chain, so when a board hangs they cannot say which stage failed (no bootloader output versus a kernel panic versus init failing to mount the root filesystem), which is the first question in any real bring-up.

Frequently asked questions

What is the difference between bare-metal, an RTOS, and embedded Linux?
They sit on a spectrum of capability versus determinism and footprint. Bare-metal runs your code directly on the hardware with no OS — smallest footprint, full control, but you build everything yourself. An RTOS (see /topics/rtos) adds a small scheduler with deterministic, hard-real-time task switching and minimal memory, ideal for microcontrollers with tight timing. Embedded Linux is a full multitasking OS with virtual memory, a process model, networking, and a huge driver and library ecosystem — but it needs an MMU, megabytes of RAM and storage, and is not hard-real-time out of the box (the PREEMPT_RT patch buys soft/firm real-time). The interview judgment is choosing correctly: hard microsecond deadlines and kilobytes of RAM point to RTOS or bare-metal; rich connectivity, a filesystem, and a complex software stack point to Linux.
What is kernel space versus user space, and why does the boundary matter?
User space is where applications run with restricted privilege and their own virtual address space; kernel space is the privileged core that manages hardware, memory, and scheduling. Code crosses the boundary through system calls, and data is copied explicitly across it (copy_to_user / copy_from_user) because a kernel must never blindly dereference a user pointer. The boundary matters because a bug in user space crashes one process, while a bug in kernel space (a bad driver pointer) can take down the whole system. Device drivers usually live in the kernel, which is why driver quality is a system-stability issue, and why interviewers probe whether you understand the cost and safety of crossing the boundary rather than treating it as a function call.
What is a device tree and why does embedded Linux need it?
A device tree is a data structure that describes hardware the system cannot discover on its own. On a PC, buses like PCIe and USB are enumerable — the OS asks the bus what is attached. On a typical embedded SoC, peripherals (UARTs, I2C controllers, GPIO, memory-mapped devices) are not self-describing, so historically that information was hard-coded in board files. The device tree replaced that: a separate .dts source, compiled to a .dtb blob, is handed to the kernel at boot and tells each driver where its hardware is (register addresses, interrupts, clocks, properties). It decouples the kernel from board specifics, so one kernel image can support many boards by swapping the device tree. Knowing what a device tree is, and that drivers match against compatible strings in it, is a baseline embedded-Linux interview signal.
What are the main classes of Linux device drivers?
Three classic classes. Character drivers handle byte-stream devices accessed sequentially (serial ports, sensors, many custom peripherals) and expose operations like open/read/write/ioctl through a device node. Block drivers handle randomly-addressable storage in fixed-size blocks (flash, disks) and plug into the block I/O and filesystem layers. Network drivers handle packet interfaces and plug into the networking stack rather than appearing as a /dev node. Most custom embedded hardware ends up as a character driver. Modern drivers also fit the kernel driver model — registering against a bus with probe() and remove() callbacks that fire when a matching device (from the device tree) appears — so you are not just writing file operations but participating in the kernel's device/driver matching.
What does the embedded Linux boot chain look like?
Power-on runs a chain of increasingly capable stages. A small ROM bootloader in the SoC loads a first-stage loader, which initializes DRAM and loads a full bootloader (commonly U-Boot). The bootloader loads the kernel image and the device tree blob into memory, passes boot arguments, and jumps to the kernel. The kernel initializes, mounts a root filesystem (which may be an initramfs first), and starts the init process (PID 1 — systemd, or a lightweight init like BusyBox on small systems), which brings up user space. Understanding this chain matters for bring-up and debugging: a board that hangs has a specific failure stage (no UART output at all versus a kernel panic versus init failing to mount rootfs), and naming the stage is how you localize the problem.
How do you cross-compile and debug embedded Linux software?
You build on a powerful host for a different target architecture using a cross-toolchain (for example an arm-linux-gnueabihf or aarch64 GCC/Clang), because the target is too constrained to compile natively. Build systems like Yocto or Buildroot assemble the toolchain, kernel, bootloader, and root filesystem into a reproducible image. Debugging spans layers: dmesg and the kernel log for driver and boot issues, /proc and /sys to inspect kernel and device state, ftrace and perf for tracing and profiling, gdb (often gdbserver on target with gdb on host) for user-space, and kgdb or JTAG for kernel-level debugging. A strong candidate names the right tool for the layer — a driver probe failure is a dmesg and device-tree question, not a gdb question.
Is Linux real-time, and when is that a problem for embedded systems?
Mainline Linux is not hard-real-time: the scheduler is throughput-oriented and interrupt latency is bounded only loosely, so a deadline measured in microseconds can be missed under load. For many embedded products that is fine — soft-real-time tasks (media, networking, UI) tolerate jitter. When deadlines are hard, you have options: apply the PREEMPT_RT patch (now largely mainlined) to make the kernel fully preemptible and bound latency to the low microseconds, offload the hard-real-time work to a separate RTOS or microcontroller core (common in asymmetric multiprocessing designs), or use a co-kernel. The interview signal is recognizing that "embedded Linux" and "hard real-time" are in tension and being able to name how you would resolve it for a given deadline.

Related topics

Essential AI-Native Skills for Embedded Linux & Device Drivers: Kernel, Device Tree, Boot

Modern engineering work increasingly uses AI tools for design and code review, debugging, documentation, test and testbench generation, and workflow automation. The goal is not to let AI replace engineering judgment — it is to move faster while keeping verification discipline.

  • Use AI to explain unfamiliar code, logs, waveforms, datasheets, or test failures.
  • Break large problems into small, reviewable steps you can verify independently.
  • Ask AI for hypotheses, then validate them against tests, measurements, simulations, or lab data.
  • Version-control your analysis scripts, testbenches, and configs — keep changes small and reviewable.
  • Document your assumptions, design tradeoffs, and debugging decisions.
  • Verify AI output before trusting it: run the checks that fit the domain — unit tests, linters, simulations, or bench/lab measurements.
  • Review AI output for correctness, edge cases, and real-world consequences.

Embedded Linux & Device Drivers: Kernel, Device Tree, Boot — coming to the question bank

The adaptive practice engine is already live for core wireless, RF, and ML systems. Embedded Linux & Device Drivers: Kernel, Device Tree, Boot isn't covered in the question bank yet — get notified when it's added.

One email when this topic launches. Nothing else. Unsubscribe in one click.