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. !../3-Resource/Platform/IOCTL in Kernel Device Drivers#3. Integrate into file_operations 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 Handling Flow

1. Interrupt Generation A hardware device (e.g., NIC, keyboard) raises an interrupt via the Programmable Interrupt Controller (PIC/APIC). The PIC converts the IRQ line into a vector number and signals the CPU via the INTR/NMI pin. 2. CPU State Save & Context Switch The CPU finishes the current instruction, saves the process context (registers, PC, flags) to the stack, and disables local interrupts Switches to the interrupt context (no associated process, interrupts disabled). 3. IDT Lookup The CPU uses the Interrupt Descriptor Table (IDT) to find the handler address for the interrupt vector. On ARM, the vector table (similar to x86 IDT) is preconfigured with handlers like handle_level_irq or handle_edge_irq. 4. Top Half Execution Immediate Actions: Acknowledge the interrupt at the hardware level (irq_data.chip->irq_ack()) Read device status registers to confirm the interrupt source Minimal Processing: Copy critical data (e.g., network packets) to kernel buffers. Schedule deferred processing via bottom halves (tasklets, softirqs) APIs: request_irq(), free_irq() for driver-level registration. 5. Bottom Half Execution Deferred Work: Process data in safe contexts (e.g., tasklet_schedule() or workqueues). Runs with interrupts enabled (softirq context) or in process context (workqueues). Mechanisms: SoftIRQs: Statically allocated, high-priority (e.g., network RX) Tasklets: Dynamically allocated, atomic (e.g., USB transfers). Workqueues: Sleepable, process context (e.g., filesystem I/O) . 6. Interrupt Completion Send End-of-Interrupt (EOI) to the PIC (e.g., irq_data.chip->irq_eoi()) The result is stored in eax/r0, and the kernel uses iret (x86) or exception return (ARM) to resume user execution. 7. Examples Network Driver (Hardware Interrupt) Top Half: irqreturn_t nic_isr(int irq, void *dev_id) { // Read packet from hardware buffer tasklet_schedule(&nic_tasklet); // Schedule bottom half return IRQ_HANDLED; } Bottom Half: void nic_tasklet_fn(unsigned long data) { // Process packets, update kernel networking stack }

May 4, 2025 · 2 min

Interrupt Questions

Q1: What happens if another interrupt occurs while a top half (ISR) is executing? Answer: By default, interrupts are disabled during the top half execution. When the CPU enters the ISR (via the IDT), it automatically clears the Interrupt Flag (IF) on x86 (using cli), preventing further interrupts until the ISR finishes. Exception: Some architectures or configurations (e.g., nested interrupts) allow interrupts to preempt an ISR. For example: IRQF_DISABLED (now deprecated): Previously controlled whether interrupts were disabled during the ISR. Modern kernels typically disable interrupts for all IRQ handlers by default. Threaded interrupts (using IRQF_ONESHOT or IRQF_THREAD): The “top half” runs in a kernel thread with interrupts enabled. Key Takeaway: ...

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 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 Interrupt Handling Flow ...

May 3, 2025 · 2 min