You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.1 KiB

Virtual Memory Layout on amd64

GayBSD's virtual memory map is based on the one from FreeBSD. The only difference is that areas for features which aren't implemented (yet) are unused. We do this because even though GayBSD is supposed to be an OS written mostly from scratch, my gut feeling somehow tells me it's better that way. Also, i trust the FreeBSD people have put way more thought into this than i probably could have ever done with my limited knowledge about the x86.

The size specifiers here are powers of two (1 KB = 1024 B).

start address offset end address size description
00000000 00000000 +0 00007fff ffffffff 128 TB userland area
00008000 00000000 +128 TB ffff7fff ffffffff ~ 1.6M TB huge ass hole
ffff8000 00000000 -128 TB ffff8040 20100fff ~ 0.25 TB recursive page table
ffff8040 20101000 ~ -127.75 TB fffff7ff ffffffff ~ 119 TB unused
fffff800 00000000 -8 TB fffffbff ffffffff 4 TB linear physical memory
fffffc00 00000000 -4 TB fffffdff ffffffff 2 TB unused
fffffe00 00000000 -2 TB ffffffff ffffffff 2 TB kernel area

Kernel address space starts counting from the end of virtual memory space downwards, therefore the offsets are negative. Likewise, user space starts from the beginning, meaning positive offsets.

The huge ass hole between user and kernel space is specified in million TB because i think it gives a better overview of the size ratios between these individual areas than just writing EB. It also kind of makes you appreciate the sheer vastness of 64-bit address space.

Kernel space addresses start at 0xffff800000000000 because the MMU "only" supports 48-bit linear addresses. The way i've understood it, the Intel spec says bits 63:48 of virtual addresses must be copies of bit 47, but other than that are ignored. So, as far as the MMU is concerned, the huge hole doesn't even exist: Userspace ranges from 0x000000000000~0x7fffffffffff, and everything belonging to the kernel from 0x800000000000~0xffffffffffff (note how the leading 0's/f's are missing, these are 48-bit values).

The linear physical memory is a direct mapping of physical RAM, which is required because kmalloc() and friends need to be able to allocate physically contiguous memory for DMA transfers and i don't have the energy to update kernel page maps every time the kernel needs a new page.

The kernel image itself is loaded into physical memory at 0x00400000 by default, and the entire low 2 GB of physical memory are statically mapped to the end of virtual memory (-2 GB). That way, we can use -mcmodel=kernel, which prevents the compiler from emitting raw address loads and absolute jumps (this is significantly faster). All kernel code resides within the -2 GB region.

The vm_page_array, which keeps track of what each individual page is used for, starts directly at the beginning of the kernel area at -2 TB.