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.
193 lines
5.8 KiB
C
193 lines
5.8 KiB
C
/* See the end of this file for copyright and license terms. */
|
|
|
|
#pragma once
|
|
|
|
/**
|
|
* @file include/gay/mm.h
|
|
* @brief Header for dynamic memory management
|
|
*
|
|
* To avoid possible confusion, physical memory addresses always use type
|
|
* `uintptr_t` and virtual ones are `void *`. This should give us at least some
|
|
* type of compiler warning if they are accidentally mixed up.
|
|
*
|
|
* GayBSD uses a classic slab algorithm for its own data structures, which is
|
|
* backed by a buddy page frame allocator. The latter is also used for getting
|
|
* bigger areas of memory that is not physically contiguous (for regular user
|
|
* allocations). The high memory is statically mapped to the area after the
|
|
* kernel image, which starts at `CFG_KERN_ORIGIN + KERN_OFFSET`. Om i386,
|
|
* this results in a kernel image mapping to `0xf0100000`.
|
|
*/
|
|
|
|
#ifdef _KERNEL
|
|
|
|
#include <arch/page.h>
|
|
|
|
#include <gay/types.h>
|
|
|
|
/**
|
|
* @brief Memory allocation flags passed to `kmalloc()`.
|
|
*/
|
|
enum mm_flags {
|
|
/** @brief Physically contiguous memory for DMA. */
|
|
MM_CONTIG = (1 << 0),
|
|
/** @brief Use emergency memory reserves if necessary. */
|
|
MM_EMERG = (1 << 1),
|
|
/** @brief Don't sleep during the allocation. */
|
|
MM_NOSLEEP = (1 << 2),
|
|
/** @brief Allocate userspace memory. */
|
|
MM_USER = (1 << 4),
|
|
/** @brief Kernel memory */
|
|
MM_KERN = MM_CONTIG,
|
|
/** @brief Allocate memory in atomic (irq) context. */
|
|
MM_ATOMIC = MM_EMERG | MM_NOSLEEP,
|
|
};
|
|
|
|
/**
|
|
* @brief Allocate memory.
|
|
*
|
|
* Memory must be released with `kfree()` after use.
|
|
*
|
|
* @param size Memory size in bytes
|
|
* @param flags Allocation flags
|
|
* @returns The allocated memory area, or `NULL` if OOM
|
|
*/
|
|
void *kmalloc(size_t size, enum mm_flags flags) __malloc_like __alloc_size(1);
|
|
|
|
/**
|
|
* @brief Release memory.
|
|
*
|
|
* @param ptr The pointer returned by `kmalloc()`.
|
|
*/
|
|
void kfree(void *ptr);
|
|
|
|
enum pflags {
|
|
PFLAG_PRESENT = __PFLAG_PRESENT,
|
|
PFLAG_RW = __PFLAG_RW,
|
|
PFLAG_USER = __PFLAG_USER,
|
|
PFLAG_ACCESSED = __PFLAG_ACCESSED,
|
|
PFLAG_DIRTY = __PFLAG_DIRTY,
|
|
PFLAG_GLOBAL = __PFLAG_GLOBAL,
|
|
PFLAG_NOCACHE = __PFLAG_NOCACHE,
|
|
#ifdef __HAVE_HUGEPAGES
|
|
PFLAG_HUGE = __PFLAG_HUGE,
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* @brief Map a page in physical memory to a virtual address.
|
|
* Remember that if `vm` is the memory map currently in use, you will most
|
|
* likely need to call `vm_update()` when you've finished mapping everything
|
|
* to flush the TLB.
|
|
*
|
|
* @param phys Physical address of the page
|
|
* @param virt Virtual address to map the page to
|
|
* @param flags Flags to apply to the page
|
|
* @returns 0 on success, or `-ENOMEM` if OOM (for allocating new page tables)
|
|
*/
|
|
int map_page(uintptr_t phys, void *virt, enum pflags flags);
|
|
|
|
/**
|
|
* @brief Remove a page mapping.
|
|
*
|
|
* @param virt Virtual address the page is mapped to, must be page aligned
|
|
* @returns The physical page address that was being mapped
|
|
*/
|
|
uintptr_t unmap_page(void *virt);
|
|
|
|
/** @brief Flush the TLB. */
|
|
void vm_flush(void);
|
|
|
|
/**
|
|
* @brief Initialize the memory allocator.
|
|
*
|
|
* This can only be called once, from the early `_boot()` routine.
|
|
*
|
|
* @param _phys_start Physical start address of the page area
|
|
* @param _phys_end Physical end address of the page area
|
|
* @returns 0 on success, or -1 if the pointers were garbage
|
|
*/
|
|
int kmalloc_init(uintptr_t _phys_start, uintptr_t _phys_end);
|
|
|
|
/** @brief Start of the mapped, physically contiguous kernel heap */
|
|
extern void *kheap_start;
|
|
/** @brief End of the mapped, physically contiguous kernel heap */
|
|
extern void *kheap_end;
|
|
|
|
/** @brief Start of the kernel heap in physical memory */
|
|
extern uintptr_t phys_start;
|
|
/** @brief End of the kernel heap in physical memory */
|
|
extern uintptr_t phys_end;
|
|
|
|
/**
|
|
* @brief Initialize the buddy page frame allocator.
|
|
* This is only called once, internally from `kmalloc_init()`.
|
|
*
|
|
* @return 0 on success, or -1 if it messed up
|
|
*/
|
|
int pages_init(void);
|
|
|
|
/**
|
|
* @brief Allocate and map a contiguous region in physical memory.
|
|
* The physical region will be mapped to its corresponding virtual address
|
|
* between `DMAP_START` and `DMAP_END`, such that the physical address can be
|
|
* calculated with `ptr - DMAP_OFFSET`.
|
|
*
|
|
* @param count Number of contiguous pages to allocate
|
|
* @param flags
|
|
* @return
|
|
*/
|
|
void *get_pages(usize count, enum mm_flags flags) __malloc_like;
|
|
|
|
void free_pages(void *ptr);
|
|
|
|
/**
|
|
* @brief Initialize the slab caches.
|
|
* This is called only once by `kmalloc_init()` after the buddy page frame
|
|
* allocator is initialized.
|
|
*/
|
|
void slab_init(void);
|
|
|
|
/**
|
|
* @brief Allocate contiguous memory from the slab caches.
|
|
* This is only used internally by `kmalloc()` and for relatively small
|
|
* objects (<< PAGE_SIZE). If you need memory, use `kmalloc()` instead.
|
|
*
|
|
* @param size Requested memory size
|
|
* @param flags Flags that are passed to `get_pages` for creating new caches
|
|
* @return The allocated pointer, or `nil` if OOM or `size` was too big
|
|
*/
|
|
void *slab_alloc(usize size, enum mm_flags flags) __malloc_like __alloc_size(1);
|
|
|
|
void slab_free(void *ptr);
|
|
|
|
/**
|
|
* @brief Return where a physical address maps to in the direct memory area.
|
|
* The returned pointer will be within the range `DMAP_START` (inclusive)
|
|
* and `DMAP_END` (exclusive).
|
|
*
|
|
* @param phys Physical address
|
|
* @return Virtual address
|
|
*/
|
|
static __always_inline void *__v(uintptr_t phys)
|
|
{
|
|
if (phys > phys_end)
|
|
return nil;
|
|
return (void *)phys + DMAP_OFFSET;
|
|
}
|
|
|
|
#endif /* _KERNEL */
|
|
|
|
/*
|
|
* This file is part of GayBSD.
|
|
* Copyright (c) 2021 fef <owo@fef.moe>.
|
|
*
|
|
* GayBSD is nonviolent software: you may only use, redistribute, and/or
|
|
* modify it under the terms of the Cooperative Nonviolent Public License
|
|
* (CNPL) as found in the LICENSE file in the source code root directory
|
|
* or at <https://git.pixie.town/thufie/npl-builder>; either version 7
|
|
* of the license, or (at your option) any later version.
|
|
*
|
|
* GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent
|
|
* permitted by applicable law. See the CNPL for details.
|
|
*/
|