driver-know-hows

device driver related stuff

View on GitHub

Chapter 0: Prerequisites and Fundamentals

Table of Contents

  1. Before You Start
  2. C Programming Essentials
  3. Linux System Fundamentals
  4. Computer Architecture Basics
  5. Build System Basics
  6. Understanding the Kernel
  7. Self-Assessment Quiz

Before You Start

What You Need to Know

Required Knowledge:

Recommended But Not Required:

Hardware:

Time Investment

Topic Time Estimate
Prerequisites Review 1-2 weeks
Basic Modules 1-2 weeks
Character Drivers 2-3 weeks
Advanced Topics 4-6 weeks
Total 8-13 weeks

C Programming Essentials

Pointers (Critical!)

/*
 * Pointers are ESSENTIAL for kernel programming
 * You must be completely comfortable with them
 */

/* Basic pointer */
int x = 42;
int *ptr = &x;      /* ptr points to x */
*ptr = 100;         /* Modify through pointer (x is now 100) */

/* Pointer to pointer */
int **pp = &ptr;    /* pp points to ptr */
**pp = 200;         /* x is now 200 */

/* Array vs pointer */
int arr[10];
int *p = arr;       /* Array name is pointer to first element */
p[5] = 42;          /* Same as arr[5] = 42 */
*(p + 5) = 42;      /* Same as above */

/* Function pointer */
int (*func_ptr)(int, int);  /* Pointer to function returning int */
func_ptr = &my_function;
int result = func_ptr(10, 20);  /* Call through pointer */

/* Pointer arithmetic */
int *p = arr;
p++;                /* Move to next int (adds sizeof(int) bytes) */
p += 5;            /* Move 5 ints forward */

/* NULL pointer */
int *p = NULL;      /* Always initialize! */
if (p != NULL) {    /* Always check before dereferencing */
    *p = 42;
}

Structures and Unions

/*
 * Structures are heavily used in kernel
 */

/* Basic structure */
struct device {
    int id;
    char name[32];
    unsigned long flags;
};

/* Typedef (less common in kernel) */
typedef struct {
    int x, y;
} point_t;

/* Structure pointers */
struct device *dev;
dev->id = 1;              /* Access via pointer (->)*/
(*dev).id = 1;            /* Same but uglier */

/* Nested structures */
struct driver {
    struct device dev;    /* Embedded structure */
    void (*init)(void);   /* Function pointer */
};

/* Bit fields */
struct flags {
    unsigned int ready:1;     /* 1 bit */
    unsigned int error:1;     /* 1 bit */
    unsigned int mode:2;      /* 2 bits */
    unsigned int reserved:28; /* Rest */
};

/* Unions (share memory) */
union data {
    int i;
    float f;
    char c[4];
};  /* All members start at same address */

/* Anonymous unions/structs (C11) */
struct packet {
    int type;
    union {
        struct { int x, y; } point;
        struct { char name[8]; } text;
    };  /* No union name needed */
};

Memory and Casts

/*
 * Understanding memory layout is critical
 */

/* Size of types */
sizeof(char)        // 1 byte
sizeof(short)       // 2 bytes (usually)
sizeof(int)         // 4 bytes (usually)
sizeof(long)        // 4 or 8 bytes (architecture dependent!)
sizeof(void *)      // 4 or 8 bytes (pointer size)

/* Type casting */
int x = 42;
void *generic = (void *)&x;          /* Generic pointer */
int *typed = (int *)generic;         /* Cast back */

/* Pointer casting (common in kernel) */
unsigned long addr = 0xFFFF8000;
void *ptr = (void *)addr;            /* Address to pointer */
unsigned long addr2 = (unsigned long)ptr;  /* Pointer to address */

/* Alignment */
struct aligned {
    char c;      /* 1 byte */
    /* 3 bytes padding on 32-bit, 7 on 64-bit */
    int i;       /* 4 bytes */
} __attribute__((aligned(8)));  /* Force 8-byte alignment */

/* Volatile (prevents optimization) */
volatile int *hw_register = (volatile int *)0x80000000;
*hw_register = 1;  /* Compiler won't optimize away */

/* Const correctness */
const int *p1;        /* Pointer to const int */
int * const p2;       /* Const pointer to int */
const int * const p3; /* Const pointer to const int */

Preprocessor

/*
 * Heavy preprocessor use in kernel
 */

/* Macros */
#define MAX_SIZE 1024
#define MIN(a, b) ((a) < (b) ? (a) : (b))  /* Always use parentheses! */

/* Multi-line macros */
#define SWAP(a, b) do { \
    typeof(a) _tmp = (a); \
    (a) = (b); \
    (b) = _tmp; \
} while (0)  /* do-while trick for safety */

/* Conditional compilation */
#ifdef DEBUG
    #define DBG_PRINT(fmt, ...) printk(fmt, ##__VA_ARGS__)
#else
    #define DBG_PRINT(fmt, ...)
#endif

/* Stringify */
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
TOSTRING(123)  /* Becomes "123" */

/* Token pasting */
#define CONCAT(a, b) a##b
CONCAT(hello, _world)  /* Becomes hello_world */

/* Common kernel patterns */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define container_of(ptr, type, member) /* See kernel headers */

Error Handling

/*
 * Kernel uses negative error codes
 */

/* Return value checking */
int ret = some_function();
if (ret < 0) {
    /* Error occurred */
    return ret;  /* Propagate error */
}

/* Common error codes */
-ENOMEM     /* Out of memory */
-EINVAL     /* Invalid argument */
-EBUSY      /* Device busy */
-EFAULT     /* Bad address */
-EIO        /* I/O error */

/* Error path with goto */
int init_device(void)
{
    int ret = 0;
    void *buf1 = NULL, *buf2 = NULL;
    
    buf1 = kmalloc(1024, GFP_KERNEL);
    if (!buf1) {
        ret = -ENOMEM;
        goto out;
    }
    
    buf2 = kmalloc(2048, GFP_KERNEL);
    if (!buf2) {
        ret = -ENOMEM;
        goto free_buf1;
    }
    
    /* Success path */
    return 0;

free_buf2:
    kfree(buf2);
free_buf1:
    kfree(buf1);
out:
    return ret;
}

Linux System Fundamentals

Essential Commands

# File operations
ls -la              # List files with details
cd /path            # Change directory
pwd                 # Print working directory
cat file            # Display file
less file           # Page through file
head -n 10 file     # First 10 lines
tail -f file        # Follow file (useful for logs)

# File editing
vim file            # Edit with vim
nano file           # Edit with nano

# Permissions
chmod 644 file      # rw-r--r--
chmod +x script     # Add execute permission
sudo command        # Run as root
chown user:group    # Change ownership

# Process management
ps aux              # List all processes
top                 # Interactive process viewer
kill PID            # Terminate process
killall name        # Kill by name

# Kernel/module commands
uname -r            # Kernel version
uname -a            # All system info
lsmod               # List loaded modules
modinfo module      # Module information
dmesg               # Kernel log
dmesg -w            # Watch kernel log
journalctl -k       # Systemd kernel log

# System information
lspci               # PCI devices
lsusb               # USB devices
lscpu               # CPU info
free -h             # Memory usage
df -h               # Disk usage

File System Hierarchy

/
β”œβ”€β”€ /boot           # Kernel and bootloader
β”‚   β”œβ”€β”€ vmlinuz-*   # Kernel image
β”‚   └── config-*    # Kernel config
β”œβ”€β”€ /dev            # Device files
β”‚   β”œβ”€β”€ sda         # Hard disk
β”‚   β”œβ”€β”€ tty*        # Terminals
β”‚   └── null        # Null device
β”œβ”€β”€ /etc            # Configuration
β”‚   └── udev/       # udev rules
β”œβ”€β”€ /home           # User directories
β”œβ”€β”€ /lib/modules    # Kernel modules
β”‚   └── $(uname -r)/
β”‚       β”œβ”€β”€ kernel/ # Built-in modules
β”‚       └── extra/  # External modules
β”œβ”€β”€ /proc           # Process/kernel info
β”‚   β”œβ”€β”€ cpuinfo     # CPU information
β”‚   β”œβ”€β”€ meminfo     # Memory info
β”‚   └── [PID]/      # Process info
β”œβ”€β”€ /sys            # Sysfs (device/driver)
β”‚   β”œβ”€β”€ class/      # Device classes
β”‚   β”œβ”€β”€ devices/    # Device hierarchy
β”‚   └── module/     # Module parameters
β”œβ”€β”€ /tmp            # Temporary files
β”œβ”€β”€ /usr            # User programs
β”‚   β”œβ”€β”€ /src        # Source code
β”‚   └── /include    # Header files
└── /var            # Variable data
    └── /log        # Log files

Understanding /proc

# Process information
cat /proc/[PID]/status    # Process status
cat /proc/[PID]/cmdline   # Command line
cat /proc/[PID]/maps      # Memory maps

# System information
cat /proc/cpuinfo         # CPU details
cat /proc/meminfo         # Memory details
cat /proc/version         # Kernel version
cat /proc/modules         # Loaded modules (like lsmod)
cat /proc/devices         # Character and block devices
cat /proc/interrupts      # Interrupt statistics

# Kernel parameters
cat /proc/sys/kernel/ostype
echo value > /proc/sys/kernel/parameter  # Modify

Understanding /sys

# Device information
ls /sys/class/              # Device classes
ls /sys/block/              # Block devices
ls /sys/bus/                # Bus types

# Module parameters
ls /sys/module/[module]/parameters/
cat /sys/module/[module]/parameters/[param]
echo value > /sys/module/[module]/parameters/[param]

# Device attributes
ls /sys/class/net/eth0/     # Network device
cat /sys/class/net/eth0/address  # MAC address

Computer Architecture Basics

Memory Hierarchy

CPU Registers (fastest, ~1 cycle)
    ↓
L1 Cache (32-64 KB, ~4 cycles)
    ↓
L2 Cache (256-512 KB, ~12 cycles)
    ↓
L3 Cache (2-32 MB, ~30 cycles)
    ↓
RAM (GB, ~100 cycles)
    ↓
SSD/HDD (TB, ~100,000+ cycles)

Memory Layout

High Address (0xFFFFFFFF)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Kernel Space          β”‚ (Ring 0, privileged)
β”‚   - Kernel code         β”‚
β”‚   - Kernel data         β”‚
β”‚   - Device drivers      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ ← Kernel/User boundary
β”‚   Stack (grows down)    β”‚
β”‚         ↓               β”‚
β”‚                         β”‚
β”‚         ↑               β”‚
β”‚   Heap (grows up)       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   BSS (uninitialized)   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Data (initialized)    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Text (code)           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Low Address (0x00000000)

CPU Modes

/*
 * x86/x64 Protection Rings
 */

Ring 0: Kernel mode (privileged)
    - Full hardware access
    - Can execute privileged instructions
    - Device drivers run here

Ring 3: User mode (unprivileged)
    - Limited access
    - Cannot access hardware directly
    - Applications run here

// Transition between modes via:
// - System calls (user β†’ kernel)
// - Interrupts (any β†’ kernel)
// - Return from interrupt (kernel β†’ user)

Interrupts and Exceptions

Hardware Interrupt:
    Device signals CPU β†’ CPU stops β†’ Saves state β†’
    Executes interrupt handler β†’ Restores state β†’ Continues

Software Interrupt (System Call):
    User program invokes syscall β†’ Switch to kernel mode β†’
    Execute kernel function β†’ Return to user mode

Exception:
    CPU detects error (div by zero, page fault) β†’
    Switch to kernel β†’ Handle exception

Build System Basics

GCC Compilation Steps

# Complete process
source.c β†’ Preprocessor β†’ preprocessed.i β†’ 
Compiler β†’ assembly.s β†’ Assembler β†’ object.o β†’ 
Linker β†’ executable

# Step by step
gcc -E source.c -o source.i    # Preprocessing only
gcc -S source.c -o source.s    # Compilation to assembly
gcc -c source.c -o source.o    # Assembly to object
gcc source.o -o program        # Linking

# All in one
gcc source.c -o program

# Common flags
gcc -Wall           # All warnings
gcc -Werror         # Treat warnings as errors
gcc -O2             # Optimization level 2
gcc -g              # Include debug symbols
gcc -I/path         # Include directory
gcc -L/path         # Library directory
gcc -lname          # Link library

Makefile Basics

# Simple Makefile
CC = gcc
CFLAGS = -Wall -Werror -g
TARGET = program
OBJS = main.o utils.o

# Default target
all: $(TARGET)

# Link
$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $(TARGET) $(OBJS)

# Compile
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

# Clean
clean:
	rm -f $(TARGET) $(OBJS)

# Phony targets
.PHONY: all clean

Kernel Module Makefile

# Kernel module Makefile structure
obj-m += mymodule.o

# If multiple source files
mymodule-objs := main.o helper.o

# Kernel build directory
KDIR := /lib/modules/$(shell uname -r)/build

# Current directory
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

.PHONY: all clean

Understanding the Kernel

Kernel vs User Space

/*
 * Key Differences
 */

// User Space:
printf("Hello\n");          // Standard C library
malloc(size);               // User space allocator
pthread_create();           // POSIX threads
sleep(1);                   // Can block freely
// Can crash without affecting system

// Kernel Space:
printk("Hello\n");          // Kernel logging
kmalloc(size, GFP_KERNEL);  // Kernel allocator
kthread_create();           // Kernel threads
msleep(1);                  // Sleep (careful!)
// Bug = system crash!

System Calls

/*
 * User space uses system calls to request kernel services
 */

// User space:
int fd = open("/dev/mydevice", O_RDWR);  // System call
write(fd, buffer, size);                  // System call
close(fd);                                // System call

// Kernel space (what actually happens):
// open() β†’ sys_open() β†’ kernel file operations
// write() β†’ sys_write() β†’ driver's write function
// close() β†’ sys_close() β†’ driver's release function

Kernel Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         System Call Interface           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Process          Memory         Networkβ”‚
β”‚  Scheduler        Management      Stack β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚         Virtual File System (VFS)       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  File Systems    Block Layer    Networkβ”‚
β”‚  (ext4, btrfs)   (I/O scheduler) (TCP)  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚           Device Drivers                β”‚
β”‚  (Character, Block, Network)            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚         Hardware Abstraction            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Self-Assessment Quiz

Test your understanding before proceeding:

C Programming

  1. What’s wrong with this code?
    int *get_pointer(void) {
     int x = 42;
     return &x;  // BUG: Returning pointer to local variable!
    }
    
  2. What does this print?
    int arr[5] = {1, 2, 3, 4, 5};
    int *p = arr + 2;
    printf("%d\n", p[1]);  // Answer: 4 (p[1] = *(p+1) = arr[3])
    
  3. Fix this macro:
    #define MAX(a, b) a > b ? a : b  // BUG: Missing parentheses
    // Correct:
    #define MAX(a, b) ((a) > (b) ? (a) : (b))
    

Linux Commands

  1. How to see last 20 lines of kernel log?
    dmesg | tail -20
    # or
    journalctl -k -n 20
    
  2. How to check if module is loaded?
    lsmod | grep module_name
    
  3. How to find which kernel version?
    uname -r
    

Concepts

  1. What’s the difference between kernel space and user space?
    • Kernel: Ring 0, full hardware access, no protection
    • User: Ring 3, limited access, protected from crashes
  2. Why can’t you use printf in kernel?
    • No standard C library in kernel
    • Use printk instead
  3. What happens during a system call?
    • Context switch from user to kernel mode
    • Kernel function executes
    • Return to user mode

Answer Key

If you got:


Next Steps

βœ… If you’re comfortable with all topics: β†’ Proceed to 01-basics.md

πŸ“š If you need more review: β†’ Study recommended books:

πŸ’» Practice exercises: β†’ Try examples in examples/00-c-review/


Quick Reference Card

Essential C Concepts

// Pointers
int *p = &x;        // Address of
int val = *p;       // Dereference

// Structures
struct dev *d;
d->member;          // Arrow operator

// Casting
(type *)pointer;    // Type cast

// Macros
#define FOO(x) ...  // With parentheses!

Essential Commands

# Module operations
lsmod               # List modules
insmod mod.ko       # Load module
rmmod mod           # Unload module
modinfo mod.ko      # Module info
dmesg               # Kernel log

# Building
make                # Build
make clean          # Clean

Memory Layout

0xFFFFFFFF  ← Kernel Space (Ring 0)
0xC0000000  ← User/Kernel boundary
            ↓ Stack (grows down)
            ↑ Heap (grows up)
0x08048000  ← Text (code)
0x00000000

Ready to write kernel code? Let’s go! β†’