Physical memory
In physical memory the kernel usually resides at a random offset above 0x1000000
. This depends on the kernel configuration options CONFIG_PHYSICAL_START
, CONFIG_PHYSICAL_ALIGN
and CONFIG_RANDOMIZE_BASE
and the kernel command line options kaslr
/nokaslr
as described in the linux-insides book.
Virtual memory (32-bit)
On 32-bit architectures the virtual address space split depends on the kernel configuration option CONFIG_PAGE_OFFSET
which is on many architectures set implicitly by the CONFIG_VMSPLIT_*
options. The configuration for your kernel is usually put alongside the kernel image into /boot/config-<version>
, so you can check for the offset where the kernel area in virtual memory begins with grep PAGE_OFFSET "/boot/config-$(uname -r)"
. The usual configuration for x86 is CONFIG_VMSPLIT_3G
which sets the PAGE_OFFSET
to 0xC0000000, reserving the upper 1 GiB of the address space for the kernel. For performance reasons this mapping is kept the same in all virtual address spaces, including all userspace processes.
The exact address where the kernel code starts is somewhere in this area and may be randomized on boot. That depends on the same configuration and kernel command line settings as the physical address randomization.
Virtual memory (64-bit)
On 64-bit architectures the situation is different because of the vastly larger address space.
The details are architecture-dependent but the kernel resides at a memory range at the top of the address space by convention.
x86-64
On x86-64 (a.k.a. AMD64) the memory layout is documented quite well. There are two possible configurations depending on the hardware support and the configuration option CONFIG_X86_5LEVEL
:
Start (4-level paging) |
Size (4-level p.) |
Start (5-level paging) |
Size (5-level p.) |
Description |
0xFFFF800000000000 |
8 TiB |
0xFF00000000000000 |
4 PiB |
guard hole, also reserved for hypervisor |
0xFFFF880000000000 |
0.5 TiB |
0xFF10000000000000 |
0.25 PiB |
LDT remap for PTI |
0xFFFF888000000000 |
64 TiB |
0xFF11000000000000 |
32 PiB |
direct mapping of all physical memory |
0xFFFFC90000000000 |
32 TB |
0xFFA0000000000000 |
12.5 PiB |
vmalloc/ioremap space |
0xFFFFEA0000000000 |
1 TB |
0xFFD4000000000000 |
0.5 PiB |
virtual memory map |
0xFFFFEC0000000000 |
16 TB |
0xFFDF000000000000 |
8 PiB |
KASAN shadow memory |
|
|
|
|
idential layout from here on |
0xFFFFFE0000000000 |
0.5 TB |
|
|
cpu_entry_area mapping |
0xFFFFFF0000000000 |
0.5 TB |
|
|
%esp fixup stacks |
0xFFFFFFEF00000000 |
64 GB |
|
|
EFI region mapping space |
0xFFFFFFFF80000000 |
512 MB |
|
|
kernel text mapping, mapped to physical address 0 |
0xFFFFFFFFA0000000 |
1520 MB |
|
|
module mapping space |
FIXADDR_START |
~0.5 MB |
|
|
kernel-internal fixmap range, variable size and offset |
0xFFFFFFFFFF600000 |
4 kB |
|
|
legacy vsyscall ABI |
So, the kernel area starts either at 0xFFFF800000000000
or 0xFF00000000000000
and the kernel code resides (usually at a randomized offset) in the area starting at 0xFFFFFFFF80000000
.
ARM64
On 64-bit ARM the memory layout is somewhat similar to the layout on x86-64. The exact split depends on the kernel configuration (4kB/64kB pages, 2/3/4-level paging):
Page size |
Paging levels |
kernel area starting address |
4 kB |
3 |
0xFFFFFF8000000000 |
4 kB |
4 |
0xFFFF000000000000 |
64 kB |
2 |
0xFFFFFC0000000000 |
64 kB |
3 |
0xFFFF000000000000 |