What Are the Memory Regions in Kernel Space? – Free Linux Device Driver Course

Linux Kernel Virtual Address Space – Memory Regions Explained
Free Linux Kernel Development Course | EmbeddedPathashala
📖 In-depth
💻 Practical
🎓 Free Course
⚙ Kernel Internals

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
⚠ Prerequisites

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).

Linux Kernel Virtual Address Space Layout (64-bit, Top to Bottom by Decreasing Address)
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.

Kernel Modules Region Key Macros
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);
💡 Note: Always use %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?

KASAN — Types of Memory Errors Detected
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.

KASAN Shadow Map — 8 bytes of Real Memory → 1 byte of Shadow
OK
OK
OK
OK
OK
OK
OK
OK
8 bytes of real memory (all accessible)
↓
0x00
1 shadow byte (0x00 = fully accessible)
 
OK
OK
OK
✘
✘
✘
✘
✘
8 bytes (first 3 OK, last 5 freed/OOB)
↓
0x03
1 shadow byte (0x03 = only first 3 bytes safe)
KASAN Shadow Region Key Macros
Macro Meaning
KASAN_SHADOW_START Start KVA of the KASAN shadow region
KASAN_SHADOW_END End KVA; size = KASAN_SHADOW_END - KASAN_SHADOW_START
⚠ Important: KASAN only works on 64-bit Linux. It is enabled by the kernel config option 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:

vmalloc vs kmalloc — Key Differences
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
vmalloc Region Key Macros
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() */
🚫 Common Mistake: Never call 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

Leave a Reply

Your email address will not be published. Required fields are marked *