Files
2020-04-07 17:39:37 +03:00

123 lines
4.8 KiB
ReStructuredText

Memory management functions
===========================
The document describes the facilities implemented for managing virtual and physical
memory and related resources.
All virtual memory is split into two spaces: kernel and user. ``0xFFFFFF0000000000``
is the boundary, any addresses beyond which are considered kernel-space and any address
lower which is user-space.
Physical memory management
--------------------------
Kernel functions can allocate physical memory using the following two functions::
uintptr_t mm_phys_alloc_page(void);
uintptr_t mm_phys_alloc_contiguous(size_t count);
These two functions return physical pointers (or ``MM_NADDR`` in case of failure).
The first one allocates and returns a single page, whereas the latter one attempts
an allocation of contiguous physical range of ``count`` 4KiB pages.
After usage, the pages can be freed using ``mm_phys_free_page()``::
void mm_phys_free_page(uintptr_t addr)
This function only deallocates a single page, so for contiguous ranges, a loop is
required::
for (size_t i = 0; i < count; ++i) {
mm_phys_free_page(addr + i * MM_PAGE_SIZE);
}
Kernel heap
-----------
For small and frequent allocations, heap is available::
void *kmalloc(size_t size);
void kfree(void *ptr);
These two functions should work exactly as ``malloc(3)``/``free(3)`` everyone's
familiar with, so no further description is needed.
Kernel virtual memory management
--------------------------------
Function useful in developing kernel features are described here. For userspace virtual
memory facilities see `Userspace memory management`_.
The kernel has lower 1GiB of physical memory mapped at ``0xFFFFFF0000000000``, which
allows for easier access to physical memory without needing to map it first.
``MM_VIRTUALIZE(addr)`` macro is used to convert a physical memory address into a
kernel-space pointer.
Likewise, ``MM_PHYS(addr)`` macro converts the virtual address to physical one.
.. warning ::
These functions don't provide any boundary check and may cause undefined behavior
if provided invalid input.
Userspace memory management
---------------------------
Userspace memory consists of two kinds of virtual regions:
1. Unique ``virt`` -> ``phys`` mappings. These always correspond to unqiue physical
pages.
2. Shared memory regions (``mmap()`` ed or any other kind). These may refer either
to shared physical memory regions, or can be file/device-mapped.
Primary function for manipulating non-shared mappings is ``mm_map_single()`` function::
int mm_map_single(mm_space_t space, uintptr_t virt, uintptr_t phys, uint64_t flags);
The function is used to map a single virtual memory page to a physical address, creating
``virt .. virt + MM_PAGE_SIZE`` -> ``phys .. phys + MM_PAGE_SIZE`` association. Currently,
only 4KiB pages can be mapped this way. The ``flags`` parameter controls permission bits
for the page and can be one of the following:
* ``MM_PAGE_USER`` --- the page is accessible from userspace code
* ``MM_PAGE_WRITE`` --- the page is writable
* ``MM_PAGE_EXEC`` --- code execution is allowed for this page
A mapped address can be queried for its corresponding physical address using
``mm_map_get()``::
uintptr_t mm_map_get(mm_space_t space, uintptr_t virt, uint64_t *flags)
Corresponding physical address is returned on success, optionally setting ``*flags``
to mapping permission bits. In case of failure (the address is not mapped), ``MM_NADDR``
is returned.
Finally, once the virtual mapping is no longer needed, it can be removed from
process' virtual address tables using ``mm_umap_single``::
uintptr_t mm_umap_single(mm_space_t space, uintptr_t virt, uint32_t size);
``size`` parameter here limits which kinds of pages are unmapped, returning ``MM_NADDR``
if trying, for example, to unmap a 4KiB page, but the virtual address actually represens
2MiB page. ``size`` takes the following values:
* 0 --- Any mapping is removed
* 1 --- 4KiB mapping is removed
On success, this function will return physical memory page address which was referred
to by ``virt`` in the memory space. Otherwise, ``MM_NADDR`` is reported.
Contiguous regions in memory spaces can be bound to physical memory using ``vmfind()``
and ``vmalloc()`` functions::
uintptr_t vmfind(const mm_space_t pd, uintptr_t from, uintptr_t to, size_t npages);
uintptr_t vmalloc(mm_space_t pd, uintptr_t from, uintptr_t to, size_t npages, uint64_t flags);
``vmfind()`` searches for a contiguous free space of ``npages`` * 4KiB pages in
``from .. to`` range and returns it. ``vmalloc()`` does the same, additionally mapping
the region to a set of physical pages with given permission ``flags``. Both functions
return ``MM_NADDR`` in case of failure.
Then, ``vmfree()`` function can be used to release the region, unmapping and freeing
physical pages.