What You Will Learn in This Free Linux Kernel Development Course Tutorial
This tutorial is part of the free Linux kernel development course at EmbeddedPathashala. Here you will learn how the Linux kernel organises its own virtual memory — called the Kernel Virtual Address Space (KVA) — and what each memory region inside it is responsible for. Understanding this is fundamental before you start writing real Linux device drivers or loadable kernel modules.
- What is the Linux kernel virtual address space and why it matters
- How the kernel VAS is split into distinct memory regions
- Kernel modules (LKMs) region and its key macros
- KASAN shadow memory region and memory bug detection
- The vmalloc region and its role in dynamic kernel memory
- Lowmem and highmem regions — direct-mapped vs optional
- Kernel static image regions (_text, _sdata, BSS)
- User VAS and how it sits below the kernel segment
- How to write a kernel module that reads and prints kernel VAS details
Before reading this tutorial from our free Linux kernel development course, you should be comfortable with:
- Basic C programming (pointers, structs, macros)
- What a Linux process is and what virtual memory means
- How to write and load a basic loadable kernel module (LKM)
- Familiarity with
printk()and kernel build system (Makefile + Kbuild)
Why Every Linux Device Driver Developer Must Understand Kernel VAS
When you write a Linux device driver or a kernel module, your code does not run in userland. It runs inside the kernel itself, sharing the same address space as the OS. This means a single bad pointer dereference in your driver can crash the entire system — there is no safety net like there is in user space.
That is why understanding how the kernel has laid out its own virtual address space is not optional. It is the foundation. Every memory allocation API you will ever call from inside the kernel — kmalloc(), vmalloc(), get_free_pages() — maps to a specific region inside the kernel VAS. Before you use them, you need to know what those regions are and why they exist.
In this tutorial — part of our free Linux kernel development course — we walk through every major region of the Linux kernel virtual address space, from the kernel modules region at the top all the way down to the user VAS at the bottom.
The Linux Kernel Virtual Address Space — A Visual Overview
On a 64-bit Linux system (x86_64 or ARM64), the total virtual address space is enormous — 264 bytes in theory. The kernel takes the upper portion of this space for itself. The lower portion is the user virtual address space (VAS). Below is an HTML diagram showing how the kernel VAS is structured from high addresses (top) to low addresses (bottom).
| Region | Kernel Macro / Symbol | Purpose |
|---|---|---|
| Kernel Modules (LKMs) | MODULES_VADDR → MODULES_END |
Static code + data of all loaded LKMs |
| KASAN Shadow (64-bit only) | KASAN_SHADOW_START → KASAN_SHADOW_END |
Memory error detection shadow map (1/8th of kernel VAS) |
| vmalloc | VMALLOC_START → VMALLOC_END |
Virtually contiguous, physically scattered allocations |
| Lowmem (Direct-mapped RAM) | PAGE_OFFSET → high_memory |
1:1 mapping of physical RAM into kernel space |
| Highmem (32-bit optional) | PKMAP_BASE |
Mapping of high-memory pages on older 32-bit systems |
| Kernel Static Image | _text, _sdata, __bss_start … |
Compiled kernel code, init, data, BSS sections |
| User VAS | TASK_SIZE |
Per-process user virtual address space (below kernel segment) |
Now let us look at each of these regions in detail. This is the level of understanding you need to become a confident Linux device driver developer.
1. The Kernel Modules (LKMs) Region
When you load a kernel module — a .ko file — using insmod or modprobe, the kernel allocates memory for the module’s code and static data from a special region called the kernel modules region. This is separate from the main kernel image region.
The reason this region exists as a dedicated area is performance. Because it sits close to the main kernel text segment, short jumps and calls (which are faster than far jumps) can be used between the kernel and any loaded module. On x86_64, the kernel modules region is typically just below the main kernel image in address space.
| Macro | Meaning |
|---|---|
MODULES_VADDR |
Start kernel virtual address of the modules region |
MODULES_END |
End KVA; total size = MODULES_END - MODULES_VADDR |
You can print these from inside a kernel module using pr_info() or printk() with the %px format specifier (which prints the actual pointer address, unlike %p which hashes it for security since kernel 4.15).
Printing Kernel Modules Region from an LKM
The following code shows how to print the kernel modules region boundaries from inside a loadable kernel module. You include <linux/module.h> and use the macros directly.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/pgtable.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("Show kernel modules region boundaries");
static int __init vas_demo_init(void)
{
pr_info("=== Kernel Modules Region ===\n");
pr_info("MODULES_VADDR : 0x%px\n", (void *)MODULES_VADDR);
pr_info("MODULES_END : 0x%px\n", (void *)MODULES_END);
pr_info("Size : %lu MB\n",
(MODULES_END - MODULES_VADDR) / (1024 * 1024));
return 0;
}
static void __exit vas_demo_exit(void)
{
pr_info("vas_demo: unloaded\n");
}
module_init(vas_demo_init);
module_exit(vas_demo_exit);
%px (not %p) when printing kernel addresses in modern kernels (4.15+). The %p specifier deliberately hashes pointer values to avoid leaking kernel addresses to potentially unprivileged readers of dmesg. Use %px only during debugging.2. The KASAN Shadow Memory Region
KASAN stands for Kernel Address SANitizer. It is a powerful dynamic memory error detection tool built into the Linux kernel. It was ported from the user-space AddressSanitizer (ASAN) tool and adapted for kernel use.
KASAN is available from kernel 4.0 onward for x86_64 and from kernel 4.4 onward for ARM64. It is a compile-time instrumentation technique — the compiler inserts checks around every memory access so that illegal accesses are caught at runtime rather than causing silent corruption or a delayed crash.
What Kind of Bugs Does KASAN Catch?
| Bug Type | What It Means | Example |
|---|---|---|
| Use After Free (UAF) | Accessing memory after it has been freed with kfree() |
Driver reads a buffer pointer after calling kfree(buf) |
| Out Of Bounds (OOB) | Reading or writing past the end of an allocated buffer | Writing to buf[size] when buffer is only size bytes |
| Buffer Underflow | Writing before the start of an allocated region | Accessing buf[-1] |
How KASAN Works — The Shadow Map Concept
KASAN uses a dedicated memory region called the shadow memory region. For every 8 bytes of kernel memory that can be allocated, KASAN keeps 1 byte of shadow state. This means the shadow region is exactly 1/8th the size of the total kernel virtual address space.
Each shadow byte encodes whether the corresponding 8 bytes of real memory are accessible (fully or partially) or poisoned (freed, not yet allocated, out-of-bounds). The compiler-inserted instrumentation checks this shadow byte on every load and store. If the shadow byte says the memory is poisoned, KASAN immediately reports the violation with full context — the guilty address, the type of access, the stack trace, and even the allocation/free history if shadow call stacks are enabled.
| Macro | Meaning |
|---|---|
KASAN_SHADOW_START |
Start KVA of the KASAN shadow region |
KASAN_SHADOW_END |
End KVA; size = KASAN_SHADOW_END - KASAN_SHADOW_START |
CONFIG_KASAN. It is typically turned off in production kernels because it adds memory overhead (the shadow region is 1/8th the kernel VAS size) and a small CPU overhead per memory access. However, you should always enable KASAN during development and testing of any kernel module or driver — it will catch bugs that would otherwise silently corrupt memory and lead to impossible-to-debug crashes later.3. The vmalloc Region
The vmalloc region is the area of kernel virtual address space from which the vmalloc() family of functions allocates memory. The key characteristic of vmalloc memory is that it is virtually contiguous but physically non-contiguous.
vmalloc vs kmalloc — What Is the Difference?
This is one of the most common questions in any Linux device driver interview or exam. Here is a clear comparison:
| Property | kmalloc() | vmalloc() |
|---|---|---|
| Physical memory | Physically contiguous | Physically scattered pages |
| Virtual memory | Contiguous | Contiguous |
| Max size (typical) | 128 KB (slab-limited) | Limited only by vmalloc region size |
| DMA-safe? | Yes (with GFP_DMA) | No — not safe for DMA |
| Speed | Faster (no page table setup needed) | Slower (page table entries must be set up) |
| Use case | Small, frequently used kernel objects | Large buffers where physical contiguity is not needed |
| Macro | Meaning |
|---|---|
VMALLOC_START |
Start KVA of the vmalloc region |
VMALLOC_END |
End KVA; size = VMALLOC_END - VMALLOC_START |
Simple vmalloc Usage Example
#include <linux/vmalloc.h>
/* Allocate 2 MB virtually contiguous */
void *buf = vmalloc(2 * 1024 * 1024);
if (!buf) {
pr_err("vmalloc failed\n");
return -ENOMEM;
}
/* Use buf ... */
vfree(buf); /* Always free with vfree(), not kfree() */
kfree() on memory allocated with vmalloc() and never call vfree() on memory from kmalloc(). This will corrupt kernel memory silently or crash the system immediately. Always match the allocator with its corresponding free function.Continue Learning — Free Linux Kernel Development Course
EmbeddedPathashala offers a completely free Linux kernel development course, Linux device drivers course, and embedded systems course. No fees. No paywalls.
Visit EmbeddedPathashala