123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- .. _highmem:
- ====================
- High Memory Handling
- ====================
- By: Peter Zijlstra <[email protected]>
- .. contents:: :local:
- What Is High Memory?
- ====================
- High memory (highmem) is used when the size of physical memory approaches or
- exceeds the maximum size of virtual memory. At that point it becomes
- impossible for the kernel to keep all of the available physical memory mapped
- at all times. This means the kernel needs to start using temporary mappings of
- the pieces of physical memory that it wants to access.
- The part of (physical) memory not covered by a permanent mapping is what we
- refer to as 'highmem'. There are various architecture dependent constraints on
- where exactly that border lies.
- In the i386 arch, for example, we choose to map the kernel into every process's
- VM space so that we don't have to pay the full TLB invalidation costs for
- kernel entry/exit. This means the available virtual memory space (4GiB on
- i386) has to be divided between user and kernel space.
- The traditional split for architectures using this approach is 3:1, 3GiB for
- userspace and the top 1GiB for kernel space::
- +--------+ 0xffffffff
- | Kernel |
- +--------+ 0xc0000000
- | |
- | User |
- | |
- +--------+ 0x00000000
- This means that the kernel can at most map 1GiB of physical memory at any one
- time, but because we need virtual address space for other things - including
- temporary maps to access the rest of the physical memory - the actual direct
- map will typically be less (usually around ~896MiB).
- Other architectures that have mm context tagged TLBs can have separate kernel
- and user maps. Some hardware (like some ARMs), however, have limited virtual
- space when they use mm context tags.
- Temporary Virtual Mappings
- ==========================
- The kernel contains several ways of creating temporary mappings. The following
- list shows them in order of preference of use.
- * kmap_local_page(). This function is used to require short term mappings.
- It can be invoked from any context (including interrupts) but the mappings
- can only be used in the context which acquired them.
- This function should be preferred, where feasible, over all the others.
- These mappings are thread-local and CPU-local, meaning that the mapping
- can only be accessed from within this thread and the thread is bound to the
- CPU while the mapping is active. Although preemption is never disabled by
- this function, the CPU can not be unplugged from the system via
- CPU-hotplug until the mapping is disposed.
- It's valid to take pagefaults in a local kmap region, unless the context
- in which the local mapping is acquired does not allow it for other reasons.
- As said, pagefaults and preemption are never disabled. There is no need to
- disable preemption because, when context switches to a different task, the
- maps of the outgoing task are saved and those of the incoming one are
- restored.
- kmap_local_page() always returns a valid virtual address and it is assumed
- that kunmap_local() will never fail.
- On CONFIG_HIGHMEM=n kernels and for low memory pages this returns the
- virtual address of the direct mapping. Only real highmem pages are
- temporarily mapped. Therefore, users may call a plain page_address()
- for pages which are known to not come from ZONE_HIGHMEM. However, it is
- always safe to use kmap_local_page() / kunmap_local().
- While it is significantly faster than kmap(), for the higmem case it
- comes with restrictions about the pointers validity. Contrary to kmap()
- mappings, the local mappings are only valid in the context of the caller
- and cannot be handed to other contexts. This implies that users must
- be absolutely sure to keep the use of the return address local to the
- thread which mapped it.
- Most code can be designed to use thread local mappings. User should
- therefore try to design their code to avoid the use of kmap() by mapping
- pages in the same thread the address will be used and prefer
- kmap_local_page().
- Nesting kmap_local_page() and kmap_atomic() mappings is allowed to a certain
- extent (up to KMAP_TYPE_NR) but their invocations have to be strictly ordered
- because the map implementation is stack based. See kmap_local_page() kdocs
- (included in the "Functions" section) for details on how to manage nested
- mappings.
- * kmap_atomic(). This permits a very short duration mapping of a single
- page. Since the mapping is restricted to the CPU that issued it, it
- performs well, but the issuing task is therefore required to stay on that
- CPU until it has finished, lest some other task displace its mappings.
- kmap_atomic() may also be used by interrupt contexts, since it does not
- sleep and the callers too may not sleep until after kunmap_atomic() is
- called.
- Each call of kmap_atomic() in the kernel creates a non-preemptible section
- and disable pagefaults. This could be a source of unwanted latency. Therefore
- users should prefer kmap_local_page() instead of kmap_atomic().
- It is assumed that k[un]map_atomic() won't fail.
- * kmap(). This should be used to make short duration mapping of a single
- page with no restrictions on preemption or migration. It comes with an
- overhead as mapping space is restricted and protected by a global lock
- for synchronization. When mapping is no longer needed, the address that
- the page was mapped to must be released with kunmap().
- Mapping changes must be propagated across all the CPUs. kmap() also
- requires global TLB invalidation when the kmap's pool wraps and it might
- block when the mapping space is fully utilized until a slot becomes
- available. Therefore, kmap() is only callable from preemptible context.
- All the above work is necessary if a mapping must last for a relatively
- long time but the bulk of high-memory mappings in the kernel are
- short-lived and only used in one place. This means that the cost of
- kmap() is mostly wasted in such cases. kmap() was not intended for long
- term mappings but it has morphed in that direction and its use is
- strongly discouraged in newer code and the set of the preceding functions
- should be preferred.
- On 64-bit systems, calls to kmap_local_page(), kmap_atomic() and kmap() have
- no real work to do because a 64-bit address space is more than sufficient to
- address all the physical memory whose pages are permanently mapped.
- * vmap(). This can be used to make a long duration mapping of multiple
- physical pages into a contiguous virtual space. It needs global
- synchronization to unmap.
- Cost of Temporary Mappings
- ==========================
- The cost of creating temporary mappings can be quite high. The arch has to
- manipulate the kernel's page tables, the data TLB and/or the MMU's registers.
- If CONFIG_HIGHMEM is not set, then the kernel will try and create a mapping
- simply with a bit of arithmetic that will convert the page struct address into
- a pointer to the page contents rather than juggling mappings about. In such a
- case, the unmap operation may be a null operation.
- If CONFIG_MMU is not set, then there can be no temporary mappings and no
- highmem. In such a case, the arithmetic approach will also be used.
- i386 PAE
- ========
- The i386 arch, under some circumstances, will permit you to stick up to 64GiB
- of RAM into your 32-bit machine. This has a number of consequences:
- * Linux needs a page-frame structure for each page in the system and the
- pageframes need to live in the permanent mapping, which means:
- * you can have 896M/sizeof(struct page) page-frames at most; with struct
- page being 32-bytes that would end up being something in the order of 112G
- worth of pages; the kernel, however, needs to store more than just
- page-frames in that memory...
- * PAE makes your page tables larger - which slows the system down as more
- data has to be accessed to traverse in TLB fills and the like. One
- advantage is that PAE has more PTE bits and can provide advanced features
- like NX and PAT.
- The general recommendation is that you don't use more than 8GiB on a 32-bit
- machine - although more might work for you and your workload, you're pretty
- much on your own - don't expect kernel developers to really care much if things
- come apart.
- Functions
- =========
- .. kernel-doc:: include/linux/highmem.h
- .. kernel-doc:: include/linux/highmem-internal.h
|