2023-12-13 02:24:25 +08:00
|
|
|
|
#ifndef MEMM_H
|
|
|
|
|
#define MEMM_H 1
|
|
|
|
|
|
|
|
|
|
#ifdef __x86_64__
|
|
|
|
|
#include <kernel/arch/x86_64/memm.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <libk/lst.h>
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 内存管理模块
|
|
|
|
|
*
|
|
|
|
|
* TODO 还没设计页回收算法
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* 最大支持1TB内存 */
|
|
|
|
|
#define MEMM_MAX_SUPPORTED_MEMORY (1024 * (1024 * (1024 * (usize)1024)))
|
|
|
|
|
|
|
|
|
|
/* 最大支持的分页数量 */
|
|
|
|
|
// 这里的页均以最小的页大小计算
|
|
|
|
|
#define MEMM_MAX_SUPPORTED_PAGES (MEMM_MAX_SUPPORTED_MEMORY / MEMM_PAGE_SIZE)
|
|
|
|
|
|
|
|
|
|
/* 只分配不映射空间 */
|
|
|
|
|
#define MEMM_ALLOC_ONLY_MEMORY (128 * 1024 * 1024)
|
|
|
|
|
|
2024-02-13 01:01:59 +08:00
|
|
|
|
typedef void *(*memm_allocate_t)(void *allocator, usize size);
|
2024-01-14 15:45:35 +08:00
|
|
|
|
typedef void (*memm_free_t)(void *allocator, void *mem);
|
|
|
|
|
|
2023-12-13 02:24:25 +08:00
|
|
|
|
/*
|
|
|
|
|
内存分配器
|
|
|
|
|
分配器对象的首地址永远是MEMM_PAGE_SIZE对齐的
|
|
|
|
|
*/
|
|
|
|
|
typedef struct __allocator_t
|
|
|
|
|
{
|
2024-02-13 02:01:23 +08:00
|
|
|
|
#define MEMM_ALLOCATOR_MAGIC_NUM 0x271fe441
|
|
|
|
|
u32 magic;
|
|
|
|
|
|
2023-12-13 02:24:25 +08:00
|
|
|
|
bool initialized;
|
|
|
|
|
|
|
|
|
|
// 在本分配器中调用allocate返回nullptr后为true
|
|
|
|
|
// 调用free后为false
|
|
|
|
|
bool full;
|
|
|
|
|
|
|
|
|
|
// 进程id,当pid=0时代表内核
|
|
|
|
|
usize pid;
|
|
|
|
|
// 分配器类型
|
|
|
|
|
usize type;
|
|
|
|
|
usize size;
|
|
|
|
|
|
|
|
|
|
// 分配器实例的allocate函数
|
|
|
|
|
// 无法分配空间返回nullptr
|
|
|
|
|
// 在size参数为0时,保证不可以分配空间,但是如果空间已满依然返回nullptr
|
2024-01-14 15:45:35 +08:00
|
|
|
|
memm_allocate_t allocate;
|
2023-12-13 02:24:25 +08:00
|
|
|
|
|
|
|
|
|
// 分配器实例的free函数
|
|
|
|
|
// 若不是allocate得到的地址则什么都不做
|
2024-01-14 15:45:35 +08:00
|
|
|
|
memm_free_t free;
|
2023-12-13 02:24:25 +08:00
|
|
|
|
|
|
|
|
|
// 分配器实例
|
|
|
|
|
// 对应`type`类型使用
|
|
|
|
|
// 在kernel/memm/allocator/中是所有的内存分配器
|
|
|
|
|
u64 allocator_instance[0];
|
|
|
|
|
} allocator_t;
|
|
|
|
|
|
|
|
|
|
typedef struct __allocator_iterator_t
|
|
|
|
|
{
|
|
|
|
|
allocator_t *allocator;
|
|
|
|
|
struct __allocator_iterator_t *left, *right;
|
|
|
|
|
} allocator_iterator_t;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
内存管理器
|
|
|
|
|
内存分配分成两个阶段:映射和分配
|
|
|
|
|
映射后的页进入allocator记录中,具体的分配工作由allocator完成
|
|
|
|
|
|
|
|
|
|
在page_map中置位、在map_with_allocator中复位、在map_with_destructed_allocator中复位
|
|
|
|
|
且不在available_pages_table中的页,是页表、程序代码段、内核代码等使用的页
|
|
|
|
|
*/
|
|
|
|
|
typedef struct __mem_manager_t
|
|
|
|
|
{
|
|
|
|
|
usize memory_size;
|
|
|
|
|
usize page_amount;
|
|
|
|
|
|
|
|
|
|
// 这里记录的数量为最小的页的数量
|
|
|
|
|
usize mapped_page_amount;
|
|
|
|
|
|
|
|
|
|
// 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被
|
|
|
|
|
// 页表映射,这部分内存不可以再映射到物理页框
|
|
|
|
|
usize alloc_only_memory;
|
|
|
|
|
#ifdef __x86_64__
|
|
|
|
|
// 在这里三种页的数量分别记录
|
|
|
|
|
usize mapped_4k_page;
|
|
|
|
|
usize mapped_2m_page;
|
|
|
|
|
usize mapped_1g_page;
|
|
|
|
|
#endif
|
|
|
|
|
// 页地图
|
|
|
|
|
// 每个bit都表示这个页是否被映射
|
|
|
|
|
u8 *page_map;
|
|
|
|
|
// 分配器页地图
|
|
|
|
|
// 每个bit表示这个页是否被内存分配器控制
|
|
|
|
|
// (不代表每个页都包含完整的分配器)
|
|
|
|
|
u8 *map_with_allocator;
|
|
|
|
|
// 分配器释放页地图
|
|
|
|
|
// 每个bit表示这个页是否曾经被内存分配器控制且现在被释放
|
|
|
|
|
// 需要取消映射
|
|
|
|
|
u8 *map_with_destructed_allocator;
|
|
|
|
|
|
|
|
|
|
// 空闲页线段搜索表
|
|
|
|
|
lst_iterator_t *available_pages_table;
|
|
|
|
|
|
|
|
|
|
// 分配器树
|
|
|
|
|
// 为方便查找,以二叉树的形式存储
|
|
|
|
|
// index=0为无效项
|
|
|
|
|
allocator_iterator_t *allocators;
|
|
|
|
|
} mem_manager_t;
|
|
|
|
|
|
|
|
|
|
mem_manager_t *memm_new(usize mem_size);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
在`start`处创建一个长度为`length`的内存分配器
|
|
|
|
|
当`pid`为0时,表示这个分配器只给内核使用
|
|
|
|
|
*/
|
|
|
|
|
allocator_t *memm_allocator_new(void *start, usize length, usize type, usize pid);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
释放分配器对象
|
|
|
|
|
|
|
|
|
|
只能被内存回收模块调用
|
|
|
|
|
*/
|
|
|
|
|
void memm_allocator_destruct(allocator_t *allocator);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
申请内存
|
|
|
|
|
pid=0时为内核分配
|
|
|
|
|
所有内存在内核空间都有对物理内存空间的直接映射,也就是线性地址与物理地址相同,称为内核地址
|
|
|
|
|
|
|
|
|
|
allocator对象在进程与内核之间传递时一律使用内核空间的映射地址
|
2024-01-16 21:38:05 +08:00
|
|
|
|
|
|
|
|
|
## 要求在返回的地址前16字节处保留8字节空间作为它所在的allocator地址,并且不需要分配器的具体实现做这个事
|
2023-12-13 02:24:25 +08:00
|
|
|
|
*/
|
2024-01-16 21:38:05 +08:00
|
|
|
|
void *memm_allocate(usize size, usize pid);
|
|
|
|
|
#define memm_addr_set_allocator(mem, allocator) \
|
2024-02-05 21:55:42 +08:00
|
|
|
|
*(allocator_t **)((void *)(mem) - 16) = allocator;
|
2024-01-16 21:38:05 +08:00
|
|
|
|
#define memm_addr_get_allocator(mem) \
|
2024-02-05 21:55:42 +08:00
|
|
|
|
((*(allocator_t **)((void *)(mem) - 16)))
|
2023-12-13 02:24:25 +08:00
|
|
|
|
|
2024-01-21 19:49:22 +08:00
|
|
|
|
void *memm_kernel_allocate(usize size);
|
|
|
|
|
|
|
|
|
|
void *memm_user_allocate(usize size, usize pid);
|
|
|
|
|
|
2023-12-13 02:24:25 +08:00
|
|
|
|
/*
|
|
|
|
|
释放内存
|
|
|
|
|
*/
|
2024-01-16 21:38:05 +08:00
|
|
|
|
void memm_free(void *mem);
|
2023-12-13 02:24:25 +08:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
寻找大小合适的一组页
|
|
|
|
|
*/
|
|
|
|
|
usize find_fitable_pages(usize page_count);
|
|
|
|
|
|
|
|
|
|
#endif
|