QCPU
  • Instruction set
  • Assembly
  • Guide
  • Snippets

On this page

  • 1 Address space
    • 1.1 Kernel space
    • 1.2 MMU: memory management unit
    • 1.3 DMAC: direct memory access controller
  • 2 Memory layout
    • 2.1 Extension space (kvariable)

Virtual memory

Physical memory mapping in userland

memory
userland
Allocators in userland in order to fully manage a process’ virtual memory.
Published

October 20, 2023

Memory is addressed with 16 bits. A segment is the upper byte of that address, being 256 bytes. Physical memory is mapped to the userspace’s virtual memory. In turn, the MMU reads from the map in order to put the link between virtual (16 bit) and physical (also 16 bit) memory.

1 Address space

QCPU has a single virtual space, divided into multiple address spaces. Each process has its own userland, whilst a kernel is always loaded on the same address offset regardless of which process is currently being executed [1] [2, Ch. 5].

                 64 KiB
                (16 bit)
0x0000                   0xC000   0xFFFF
   |------------------------|--------|
   | userland               | kernel |
     48 KiB                   16 KiB

A kernel can be loaded from address 0xC000 (which may be customisable1). QCPU will signal a segmentation fault when processes residing in userspace attempt to access the kernel address space when not in a privileged CPU mode. Likewise, trying to perform write instructions to segments with the unmapped or readonly flags will also signal a segfault.

1.1 Kernel space

Kernel space is divided into two parts. Text and global mutable data of the kernel is loaded in the first part. It primarily has all fixed kernel structures ready to be used. It also includes the kernel memory map, which maps the second part of the kernel space to physical memory2. It allows the kernel to generically modify data whilst still being in the virtual context [1]:

  • ‘Fixed’ kernel space;
  • ‘Variable’ kernel space.
                      16 KiB
          0xC000      0xF000      0xFFFF
             |-----------|-----------|
 | userland  | kfixed    | kvariable |
               12 KiB      4 KiB

System calls (like any other hardware interrupt) put the CPU into kernel mode and jump to designated parts of kernel space, which doesn’t trigger a segfault:

mldw sfb, 3      ; load address of string from stack
imm  rz,  0x00   ; mask 0
sysc @fopen

Putting the CPU out of kernel mode is done by jumping out of the kernel section.

1.2 MMU: memory management unit

Address spaces are stored by reading from designated areas of the memory. In order to bootstrap the space, the fixed kernel space is set through the MMU device (specifically, the DMAC interface). A set segment in fixed kernel space directs which variable kernel space segments are loaded. Lastly, a set segment in variable kernel space directs which userspace segments are loaded.

Cleverly, this allows the kernel to switch userland processes by performing a couple of memory instructions: setting the userspace mapping reference in fixed kernel space. Flushing the MMU reloads its values, which a jump can take effect.

                 64 KiB
             /-------------\
 {           } /---------{ |         }
 |-----------|[M]--------|[M]--------|
 | userland  | kfixed    | kvariable |
   48 KiB      12 KiB      4 KiB

Figure above depicts the memory map chain from kfixed, to kvariable, to userland. kfixed is a special section mapped by the MMU through the DMAC interface.

1.3 DMAC: direct memory access controller

A DMAC operates the MMU and its managed memory. Through it’s I/O (device 1, as device 0 is the master boot device) interface, only operable in kernel mode and mapped to a section in fixed kernel space, reading from and writing to its registers controls the physical operations on memory.

  • 0 : kfixedl: an address to the section of 12 KiB of linear physical memory;
  • 1 : kfixedh: high byte of the above.

A ‘boot sector’ of a filesystem is executed in kernel mode at address 0xF000, which aims to overlay its kernel address space from the boot firmware into the specific filesystem’s kernel by setting the appropriate kfixed* registers of the DMAC.

2 Memory layout

For the userland, memory is divided into multiple sections per the process memory map. In between the square brackets is the amount of segments necessary for that section. Kernel objects are laid out the same with the only exceptions being that mappings (i.e. heap) don’t function.

userland 48K |[I][G][LLL][N][TTTT]stack... ...heap|
kfixed   12K |[I][G][MLL][N][TTTT]stack...|
kvariable 4K |[M]data... ext...|
  • I: instance data (indirectly mutable)
    • pointers to global, text, stack, sig/int/sysc map
    • for kernel: memory and sysc maps ptrs
    • for userspace: signal map ptr, process/thread ids
    • for userspace: context register copy
  • G: globals (mutable)
  • L: g(l)obals extension (mutable)
    • pointed to by globals
  • T: text (readonly)
  • M: memory map
  • N: sig/int/sysc table
    • for kernel: hardware interrupts, including internal interrupts and syscall map
    • for userspace: process signal map
Note

TODO: shared objects and their address offsets in relation with store/loads, research dynamic linkers

TODO: custom memory layout through linker script

2.1 Extension space (kvariable)

Kernel extensions (including filesystem extensions) are loaded at a specific address in kvariable space in order to be dynamically loaded. Having them be dynamically mapped removes total space overhead compared to loading it into kfixed space at all times [1].

Bootable partitions are also loaded in kvariable space by the initial boot sector. Section 1.3 explains the exact DMAC behaviour.

References

[1]
“Address space.” Linux. Available: https://linux-kernel-labs.github.io/refs/heads/master/lectures/address-space.html
[2]
Memory management. arm, 2019. Available: https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/Learn%20the%20Architecture/LearnTheArchitecture-MemoryManagement-101811_0100_00_en.pdf?revision=01a01804-ca64-4e19-a55e-2af56afea5a5

Footnotes

  1. Current documentation assumes userland, kfixed and kvariable are hardwired address sections.↩︎

  2. Kernel details depend on implementation.↩︎