This is the second post in the Linux kernel series. The first part of the series was about memblock. This week, the topic is HIGHMEM.

What is HIGHMEM?

The Linux kernel virtualizes its memory. Virtual memory addresses, which can be used by programs, are mapped to physical memory addresses. When the size of the physical memory exceeds the (maximum) size of the virtual memory, it is not possible for the kernel to map every physical address to a virtual address. So the kernel uses temporary mappings when it wants to access part of the physical memory that is not mapped to a permanent virtual memory address. The part of physical memory that does not have a permanent mapping to a virtual address is called high memory (HIGHMEM).[1]

Source: https://linux-kernel-labs.github.io/refs/heads/master/labs/memory_mapping.html#overview

HIGHMEM is often needed in 32 bit systems. A 32 bit address can represent at most 232 = 4,294,967,296 different addresses, which is approximately 4 GB (or exactly 4 GiB). But many systems have more than 4 GB of physical memory.

The available virtual memory space has to be divided between kernel space and user space. A common split is 3 : 1 user space : kernel space, which would mean 3 GB for user space and 1 GB for kernel space on a 32 bit system. The part of kernel space that has a direct mapping to a permanent physical memory is called LOWMEM. LOWMEM is contiguously mapped in physical memory.[2]

Creating Temporary Maps

There are several different functions for creating temporary virtual maps.[2]

  • vmap(): used to map multiple physical pages into a contiguous virtual address space for a long duration
  • kmap(): used to map a single physical page for a short duration. Prone to deadlocks when nested, and not recommended in new code
  • kmap_atomic(): used to map a single physical page for a very short duration. It performs well because it is restricted to the CPU that issued it, but the issuing task must stay on the same CPU until it finishes.
  • kmap_local_page(): recently developed as a replacement for kmap(). It creates a mapping that is restricted to local use by a single thread of execution. This function is preferred over the other functions and should be used when possible.[3]

References

  1. High Memory Handling — The Linux Kernel documentation
  2. Memory Mapping — The Linux Kernel documentation
  3. LKML Mailing List