Embedded Linux Boot Process on ARM

“Before Linux prints its first log, the CPU has already taken a long, carefully choreographed journey.” The Embedded Linux boot process is best understood by tracking where the CPU executes from at each stage. From power-on to a running kernel, execution moves through ROM → SRAM → DRAM. Kernel booting begins only when the CPU starts executing kernel code from RAM. 1. Power-on and CPU reset Everything starts with power-on or a hardware reset. ...

January 11, 2026 · 3 min

Character Device Management in Kernel Drivers

Overview Character devices are distinguished by the fact that they are accessed as a stream of bytes, much like a file. A character driver is responsible for implementing this behavior by mapping standard system calls to device-specific operations. Unlike block devices, which require an intermediate layer for buffering and management, character devices communicate directly with the Virtual File System (VFS). In the Linux kernel, character devices are identified by a major number (identifying the driver) and a minor number (distinguishing between specific device instances). ...

January 3, 2026 · 6 min

Move KO inside QEMU Environment using SSH

The most powerful tool you can have is the ability to move information freely. Efficiently transferring files between your host machine and a QEMU‑emulated Buildroot system becomes essential when testing kernel modules, applications, or firmware artifacts. This guide explains how to enable SSH inside Buildroot, verify connectivity, and use scp to move files seamlessly from host to guest. Prerequisite Before proceeding, ensure your Buildroot filesystem includes the OpenSSH server. Inside Buildroot, enable: ...

December 8, 2025 · 2 min

Make Simple Kernel Module (.ko)

1. Overview A kernel module provides a way to extend kernel functionality without rebuilding the entire kernel. Using the Buildroot toolchain ensures the module is ABI‑compatible with the kernel generated during your Buildroot build. QEMU then offers a convenient emulation environment to test modules without hardware. Linux kernel modules are dynamically loadable pieces of code that extend the functionality of the kernel without requiring a reboot or recompilation. They are widely used for device drivers, filesystems, and various kernel extensions. ...

November 25, 2025 · 3 min

Buildroot on QEMU

Overview Buildroot is a powerful tool that automates building cross‑compilers, kernel images, bootloaders, root filesystems, and entire minimal Linux environments. Combined with QEMU, it provides a fast and fully emulated setup without needing physical hardware. Steps 0. Dependencies Before building Buildroot, ensure the following packages are installed on your host system: For Debian/Ubuntu: sudo apt install build-essential git wget cpio unzip rsync bc python3 \ qemu-system-arm qemu-system-misc qemu-utils flex bison libssl-dev For Fedora: ...

November 25, 2025 · 3 min

Generating Package Patch for Buildroot

Generating a Patch Using diff 1. Extract the Original Source Ensure you have a pristine copy of the original source for comparison. You can extract it from the tarball in the dl directory: tar -xf dl/<package>-<version>.tar.gz -C /tmp/ This will create a directory like /tmp/<package>-<version>/. Using buildroot’s mechanism Clean the build directory and apply current patches of buildroot make <pkg>-dirclean # Remove <pkg> build directory make <pkg>-extract # Extract <pkg> sources make <pkg>-patch # Apply patches to <pkg> (Optional) cp -r output/build/<package> /tmp/ 2. Generate the Patch Use the diff command to create a unified diff between the original and modified sources: ...

May 20, 2025 · 2 min

Boot to recovery filesystem

Process Mount recovery partition into temporary location mkdir -p /mnt/recovery mount /dev/mmcblk0p6 /mnt/recovery Prepare old_root directory mkdir -p /mnt/recovery/mnt/old_root Switch root using pivot_root cd /mnt/recovery pivot_root . mnt/old_root Now: New root is /mnt/recovery (i.e., /) The previous root (e.g., initramfs or mainfs) is now mounted at /mnt/old_root Note: The chroot must be available under the old root and under the new root(recovery) Remount /proc, /sys, /dev, etc mount -t proc proc /proc mount -t sysfs sysfs /sys mount -o bind /mnt/old_root/dev /dev mount -o bind /mnt/old_root/tmp /tmp mount -o bind /mnt/old_root/run /run Start a shell inside of new root exec /bin/sh Mount root filesystem from NFS Setup nfs-service on host machine (refer [3-Resource/Linux/NFS|this]({< ref “/posts/3-resource/linux/nfs|this/” >}})) Mount NFS filesystem into the board mount -t nfs -o nolock 192.168.1.27:/home/rishav/Public /mnt/nfsroot Mount ext image as a loopback device mkdir -p /mnt/local cp /mnt/nfs/rootfs.ext4 /tmp/rootfs.ext4 mount -o loop /tmp/rootfs.ext4 /mnt/local References Manual page of pivot_root Also see difference between pivot_root and chroot

May 15, 2025 · 1 min

CPU Execution States on ARM

1. Overview Process Context The kernel executes code on behalf of a user-space process (e.g., handling a system call like read() or write()). Key Properties: Associated with a struct task_struct (process descriptor). Can sleep (use blocking functions like mutex_lock()). Can access user-space memory (via copy_from_user()). Interrupt Context “Atomic context” or “Interrupt context”, The kernel executes code to handle a hardware interrupt or softirq (e.g., a network packet arriving) Key Properties: No associated process (current macro points to an idle task). Cannot sleep (blocking functions like kmalloc(GFP_KERNEL) are forbidden). Runs with interrupts disabled (on the current CPU). 2. CPU Execution States in ARM ARM architectures (e.g., ARMv8-A) define exception levels (ELs) that correspond to CPU execution states: ...

May 4, 2025 · 3 min

System Call (Software Interrupt)

1. System Call Basics System calls (syscalls) are the interface for user-space programs to request services from the kernel. Examples include: File I/O: read(), write(), open(), close(). Device Control: ioctl(). Signal Handling: kill(), signal(). 2. System Call Table and Registration Syscall Table: A table (sys_call_table) maps syscall numbers to handler functions. Architecture-Specific: x86: Defined in arch/x86/entry/syscalls/syscall_64.tbl. ARM: Defined in arch/arm/tools/syscall.tbl. Registration: Syscalls are registered at compile time using macros like SYSCALL_DEFINE (e.g., SYSCALL_DEFINE3(write, ...) for write()). For custom syscalls (rare and discouraged), you would: Add an entry to the syscall table. Define the handler using SYSCALL_DEFINE. Recompile the kernel (or use modules for dynamic insertion). 3. Flow of System Calls 1. User-Space Invocation The libc wrapper (e.g., read(), ioctl()) triggers a software interrupt (int 0x80 on x86) or uses the syscall instruction (modern x86/ARM). // User-space code fd = open("/dev/mydevice", O_RDWR); // Syscall 1: open() read(fd, buf, 100); // Syscall 2: read() ioctl(fd, MY_CMD, arg); // Syscall 3: ioctl() close(fd); // Syscall 4: close() 2. Transition to Kernel Mode Switches to kernel mode (ring 0 on x86, EL1 on ARM). Saves user-space registers (e.g., RIP, RSP, EFLAGS). Jumps to the kernel’s syscall entry point (e.g., entry_SYSCALL_64 on x86) 3. Syscall Dispatching Syscall Number: The syscall number is stored in a register (e.g., RAX on x86, R7 on ARM). Example: __NR_read (syscall number for read()). Syscall Table: The kernel uses sys_call_table (array of function pointers) to find the handler. Example: sys_call_table[__NR_read] points to sys_read(). 4. Handler Execution in Process Context Generic Steps for All Syscalls: Argument Validation: Check pointers (e.g., buf in read()) using access_ok() Copy arguments from user space with copy_from_user() or get_user() Kernel Function Execution: Perform the requested operation (e.g., read from a file, send an ioctl command) File Operations (read/write): File Descriptor Resolution: Convert fd to a struct file using fdget(). Check file permissions (FMODE_READ/FMODE_WRITE). Driver Interaction: Call the read/write method from the file’s file_operations struct. Example: For /dev/mydevice, this invokes the driver’s .read function. I/O Control (ioctl): The ioctl syscall (sys_ioctl()) calls the driver’s .unlocked_ioctl method. 5. Return to User Space: Result is stored in eax/r0, and the kernel restores user registers Execute iret (x86) or exception return (ARM) to resume user-mode execution. 4. Device File Operations Character devices (e.g., /dev/char_dev) expose operations via file_operations: ...

May 4, 2025 · 4 min

Interrupt

Overview An interrupt is a signal that breaks the normal execution flow to handle an event. When an interrupt occurs, the CPU pauses its current task, jumps to an interrupt service routine (ISR), and after the ISR completes it resumes the original task. In other words, interrupts let hardware or software requests “call” the CPU’s attention immediately, then let the program continue “as if nothing happened” after handling it. Why are interrupts needed? Avoid Polling: More efficient than continuously checking device status (polling), reducing CPU overhead and increasing system throughput Real-Time Responsiveness: Essential for systems requiring quick reactions to events Automotive airbag systems detecting collisions Network Interface Cards (NICs) processing incoming packets Interrupt Types Hardware Interrupts: Triggered by devices (e.g., keyboard, NIC). Managed by the Programmable Interrupt Controller (PIC) or APIC. Software Interrupts: Generated by software (e.g., int 0x80 for syscalls). Exceptions: CPU-generated (e.g., divide-by-zero, page faults). How the Kernel Registers Interrupts [3-Resource/Platform/Interrupt Descriptor Table (IDT)]({< ref “/posts/3-resource/platform/interrupt-descriptor-table-(idt)/” >}}) Initialization: At boot, the kernel populates the IDT with default handlers (e.g., for exceptions). Hardware interrupts are mapped to a generic entry (e.g., common_interrupt on x86). Device Drivers: Drivers request a specific IRQ (Interrupt Request Line) using request_irq(). Example: int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev); irq: The interrupt number (e.g., IRQ 1 for keyboard). handler: The ISR function. flags: Options like IRQF_SHARED for shared interrupts. dev: A cookie passed to the ISR (used for shared IRQs). What happens when an interrupt is occurred? See [3-Resource/Platform/Interrupt Handling Flow]({< ref “/posts/3-resource/platform/interrupt-handling-flow/” >}}) ...

May 3, 2025 · 2 min