Fundamentals 9 min read

Inside Linux Kernel Boot on ARM: Decompression, MMU Setup & Page Tables

The article explains the Linux kernel boot process on ARM platforms, covering how the bootloader loads and decompresses the gzipped kernel image, the entry points of the compressed zImage, the early serial output, the initialization of the MMU and page tables, and the transition to the main C kernel code.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Inside Linux Kernel Boot on ARM: Decompression, MMU Setup & Page Tables

Linux Kernel Loading Process

The Linux kernel is typically stored as a gzipped image. The bootloader copies the compressed image into RAM, the kernel self‑decompresses, and execution continues from the decompressed code.

Location of Compiled Kernel Images

./vmlinux

– uncompressed ELF kernel image. arch/arm/boot/compressed/vmlinux – compressed ELF kernel image. arch/arm/boot/zImage – final compressed kernel image used by the bootloader.

Entry Point of the Compressed Kernel (zImage)

The linker script /arch/arm/boot/compressed/vmlinux.lds defines the link order and places the entry symbol _start in the .start section.

Early execution begins in /arch/arm/boot/compressed/head.S. The sequence performed there is:

Detect available system memory.

Initialise the area that will hold the C code.

Branch to the C function decompress_kernel defined in arch/arm/boot/compressed/misc.c.

Early Serial Output Before Decompression

The function used for early serial output is puts, defined in include/asm-arm/arch-s3c2410/uncompress.h. After decompression the boot code jumps to register r5, which contains the kernel’s start address.

Transition to the Real Linux Kernel

The real kernel entry point is in arch/arm/kernel/head-armv.S. The steps are:

Identify the processor type via __lookup_processor_type and __lookup_architecture_type.

Create temporary page tables with __create_page_tables.

Initialise the C code region.

Branch to the C function start_kernel (defined in init/main.c).

ARM MMU Overview

The Memory Management Unit (MMU) translates virtual addresses to physical addresses, enforces access permissions, and controls cache behaviour.

Memory Access Through the MMU

The MMU first looks up the virtual address in the Translation Lookaside Buffer (TLB).

If the entry is missing, hardware walks the page tables in main memory to obtain the translation and associated permissions.

MMU Page Table Granules

The ARM MMU supports four granule sizes:

Section – 1 MiB

Large page – 64 KiB

Small page – 4 KiB

Tiny page – 1 KiB

Page Table Levels

Two levels of page tables reside in RAM:

Level‑1 table stores section descriptors and pointers to Level‑2 tables.

Level‑2 table stores descriptors for large, small, and tiny pages.

Level‑1 Descriptor Layout

Each Level‑1 entry describes how a 1 MiB virtual region is mapped. Important bits are:

Bits[1:0] – descriptor type (10b for a section).

Bits[3:2] – cache and buffer flags.

Bits[4] – implementation‑defined.

Bits[8:5] – domain.

Bits[11:10] – access permissions (AP).

Bits[31:20] – section base address (high 12 bits of the physical address).

Section Translation Example

The diagram below illustrates how a virtual address is translated using a section descriptor.

Section translation diagram
Section translation diagram

Creating Temporary Kernel Page Tables (__create_page_tables)

__create_page_tables:
pgtbl   r4  @ page table address (0x30008000‑0x4000)
mov     r0, r4      @ r0 = 0x30004000 (start of Level‑1 table)
mov     r3, #0
add     r2, r0, #0x4000   @ r2 = end address of the table
1:  str r3, [r0], #4     @ clear one entry (4 bytes)
str r3, [r0], #4
str r3, [r0], #4
str r3, [r0], #4
teq r0, r2
bne 1b

This loop zero‑initialises the Level‑1 page‑table region from 0x30004000 to 0xa0080000.

krnladr r2, r4   @ r2 = start of the kernel image

With r4 = 0xa0004000, r2 points to the 1 MiB‑aligned kernel base at 0x30000000.

add r3, r8, r2   @ r8 holds MMU page‑table flags (e.g., 0xc0e)

The resulting value r3 = 0x30000c0e encodes the section base address and the required MMU flags.

str r3, [r4, r2, lsr #18]   @ identity mapping entry

Writes 0x30000c0e to address 0x300068000, establishing a 1 MiB identity mapping for the kernel.

add r0, r4, #(TEXTADDR & 0xff000000) >> 18   @ base of page‑table entries
bic r2, r3, #0x00f00000                     @ clear lower bits for PAGE_OFFSET
str r2, [r0]          @ PAGE_OFFSET + 0 MiB entry
add r0, r0, #(TEXTADDR & 0x00f00000) >> 18   @ next entry
str r3, [r0], #4      @ KERNEL + 0 MiB entry

Further entries are generated in the same manner to map the kernel’s virtual address space.

Mapping Table Visualisation

Mapping table
Mapping table

Resulting Memory Map

Resulting mapping
Resulting mapping

Transition to C Code (start_kernel)

The C entry point is the function start_kernel in init/main.c. Its early actions are:

Initialise the printk subsystem for kernel logging.

Re‑initialise the page tables with the final kernel mappings.

Set up interrupt handling via trap_init.

Initialise the system timer, console, and other core services.

Create the first kernel thread named init, which subsequently starts user‑space init processes.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

KernelLinuxARMMMUpage-tablesboot
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.