重构C语言部分的内存分配器
This commit is contained in:
parent
b0b790fab8
commit
00d655c468
|
@ -2,6 +2,7 @@
|
|||
name = "metaverse"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
# 此Cargo.toml仅用于rust-analyzer识别rust部分的代码
|
||||
# 不应使用cargo编译
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
*/
|
||||
#define MEMM_PAGE_SIZE 4096
|
||||
|
||||
#define MEMM_PAGE_TABLE_SIZE 4096
|
||||
|
||||
typedef enum __memm_page_size
|
||||
{
|
||||
MEMM_PAGE_SIZE_4K = 1, // 1个4KB页大小
|
||||
|
|
|
@ -24,11 +24,13 @@
|
|||
/**
|
||||
* @name MEMM_ALLOC_ONLY_MEMORY
|
||||
*
|
||||
* 只分配不映射空间,暂时为固定值`128MB`。物理地址`0`\~`MEMM_ALLOC_ONLY_MEMORY`的空间在进入内核前已经映射至内核空间。
|
||||
* 只分配不映射空间,暂时为固定值`64MB`。物理地址`0`\~`MEMM_ALLOC_ONLY_MEMORY`的空间在进入内核前已经映射至内核空间。
|
||||
*
|
||||
* 这段内存空间包含**1MB以内低地址**、**内核镜像**以及未分配空间,未分配空间被一个分配器独占。
|
||||
*/
|
||||
#define MEMM_ALLOC_ONLY_MEMORY (128 * 1024 * 1024)
|
||||
#define MEMM_ALLOC_ONLY_MEMORY (64 * 1024 * 1024)
|
||||
|
||||
#define MEMM_PAGE_TABLE_AREA_MAX (4 * 1024 * 1024)
|
||||
|
||||
/**
|
||||
* @name memm_allocate_t, memm_free_t
|
||||
|
@ -126,10 +128,6 @@ typedef struct __allocator_t
|
|||
// 调用分配器的`free`方法时设为`false`。
|
||||
bool full;
|
||||
|
||||
// 进程标志服,表示此分配器所属的进程,为0代表属于内核。
|
||||
usize pid;
|
||||
// 若分配器不属于内核,此成员储存此分配器的用户空间地址。
|
||||
void *userspace;
|
||||
// 分配器类型。在目录`include/kernel/memm/allocator`中对每个分配器分别定义一个唯一值。
|
||||
usize type;
|
||||
usize size;
|
||||
|
@ -144,75 +142,23 @@ typedef struct __allocator_t
|
|||
u64 allocator_instance[0];
|
||||
} allocator_t;
|
||||
|
||||
typedef struct __allocator_iterator_t
|
||||
{
|
||||
allocator_t *allocator;
|
||||
struct __allocator_iterator_t *left, *right;
|
||||
} allocator_iterator_t;
|
||||
|
||||
/**
|
||||
* @name 内存管理器
|
||||
*
|
||||
* @internal alloc_only_memory
|
||||
*
|
||||
* 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被页表映射,这部分内存不可以再映射到物理页框。
|
||||
*
|
||||
* @internal mapped_page_amount
|
||||
*
|
||||
* 已经映射的页数量。若不是最小的页会被视作多个最小页计数。
|
||||
*
|
||||
* @internal mapped_4k_page, mapped_2m_page, mapped_1g_page
|
||||
* @addindex 平台依赖宏 x86_64
|
||||
*
|
||||
* 分别记录已经映射的三种大小页的数量。
|
||||
*
|
||||
* @internal page_map
|
||||
*
|
||||
* 页地图,每个bit表示对应的最小页是否被映射。
|
||||
*
|
||||
* @internal allocator_map
|
||||
*
|
||||
* 分配器地图。每个bit表示对应的最小页是否被一个分配器控制。
|
||||
*
|
||||
* @internal destructed_allocator_map
|
||||
*
|
||||
* 释放的分配器页地图。每个bit表示对应的最小页是否曾经被分配器控制并且现在控制这个页的分配器已经释放。
|
||||
*
|
||||
* 值为1的bit位对应的最小页可以直接**取消映射**、**重新构造一个分配器**、**加载可执行程序**等。
|
||||
*
|
||||
* @internal available_pages_table
|
||||
*
|
||||
* 空闲页线段搜索表。
|
||||
*
|
||||
* @internal allocators
|
||||
*
|
||||
* 分配器二叉树。
|
||||
*/
|
||||
typedef struct __mem_manager_t
|
||||
{
|
||||
usize memory_size;
|
||||
usize page_amount;
|
||||
|
||||
// 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被页表映射,这部分内存不可以再映射到物理页框
|
||||
usize alloc_only_memory;
|
||||
|
||||
// 已经映射的页数量。若不是最小的页会被视作多个最小页计数。
|
||||
usize mapped_page_amount;
|
||||
memm_page_counter platformed_page_counter;
|
||||
allocator_t *kernel_base_allocator;
|
||||
|
||||
// 页地图。每个bit都表示这个页是否被映射。
|
||||
u8 *page_map;
|
||||
// 分配器页地图。每个bit表示这个页是否被内存分配器控制。
|
||||
u8 *allocator_map;
|
||||
// 释放的分配器页地图。每个bit表示这个页是否曾经被内存分配器控制且现在被释放。
|
||||
// 值为1的bit位对应的最小页可以直接**取消映射**、**重新构造一个分配器**、**加载可执行程序**等。
|
||||
u8 *destructed_allocator_map;
|
||||
|
||||
// 空闲页线段搜索表
|
||||
lst_iterator_t *available_pages_table;
|
||||
|
||||
// 分配器二叉树
|
||||
allocator_iterator_t *allocators;
|
||||
usize page_table_area;
|
||||
} memory_manager_t;
|
||||
|
||||
/**
|
||||
|
@ -261,23 +207,6 @@ allocator_t *memm_allocator_new(void *start, usize length, usize type, usize pid
|
|||
*/
|
||||
void memm_allocator_destruct(allocator_t *allocator);
|
||||
|
||||
/**
|
||||
* @name memm_allocate
|
||||
*
|
||||
* ```c
|
||||
* void *memm_allocate(usize size, usize pid);
|
||||
* ```
|
||||
*
|
||||
* 申请内存。`pid`为0时为内核分配。
|
||||
*
|
||||
* 所有内存在内核空间都有对物理内存空间的直接映射。
|
||||
*/
|
||||
void *memm_allocate(usize size, usize pid);
|
||||
#define memm_addr_set_allocator(mem, allocator) \
|
||||
*(allocator_t **)((void *)(mem)-16) = allocator;
|
||||
#define memm_addr_get_allocator(mem) \
|
||||
((*(allocator_t **)((void *)(mem)-16)))
|
||||
|
||||
/**
|
||||
* @name memm_kernel_allocate
|
||||
*
|
||||
|
@ -289,17 +218,6 @@ void *memm_allocate(usize size, usize pid);
|
|||
*/
|
||||
void *memm_kernel_allocate(usize size);
|
||||
|
||||
/**
|
||||
* @name memm_user_allocate
|
||||
*
|
||||
* ```c
|
||||
* void *memm_user_allocate(usize size, usize pid);
|
||||
* ```
|
||||
*
|
||||
* 为用户空间申请内存。
|
||||
*/
|
||||
void *memm_user_allocate(usize size, usize pid);
|
||||
|
||||
/**
|
||||
* @name memm_free
|
||||
*
|
||||
|
@ -311,14 +229,6 @@ void *memm_user_allocate(usize size, usize pid);
|
|||
*/
|
||||
void memm_free(void *mem);
|
||||
|
||||
/**
|
||||
* @name find_fitable_pages
|
||||
*
|
||||
* ```c
|
||||
* usize find_fitable_pages(usize page_count);
|
||||
* ```
|
||||
* 寻找大小合适的一组连续页
|
||||
*/
|
||||
usize find_fitable_pages(usize page_count);
|
||||
void *memm_allcate_pagetable();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,8 +10,6 @@ typedef struct __raw_allocator_cell
|
|||
{
|
||||
usize capacity; // 是content的长度
|
||||
usize length; // 是实际使用的长度
|
||||
allocator_t *allocator; // 所在的分配器
|
||||
usize reserved;
|
||||
u8 content[0];
|
||||
} raw_allocator_cell;
|
||||
#define raw_allocator_next_cell(cell) (raw_allocator_cell *)((void *)((cell)->content) + (cell)->capacity)
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
map_pageframe_to((u64)addr, (u64)addr, false, true, MEMM_PAGE_SIZE_4K);
|
||||
|
||||
// 这里的physical必须保证根据ps对齐
|
||||
static void map_pageframe_to(u64 target, u64 physical,
|
||||
bool user, bool write, memm_page_size ps)
|
||||
static void map_pageframe_to(
|
||||
u64 target, u64 physical,
|
||||
bool user, bool write, memm_page_size ps)
|
||||
{
|
||||
if (!is_cannonical(target))
|
||||
return;
|
||||
|
@ -22,7 +23,7 @@ static void map_pageframe_to(u64 target, u64 physical,
|
|||
PDPT = (u64 *)memm_entry_get_address(pml4e);
|
||||
else
|
||||
{
|
||||
PDPT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE);
|
||||
PDPT = memm_allcate_pagetable();
|
||||
map_pagemap(PDPT);
|
||||
memset(PDPT, 0, MEMM_PAGE_SIZE);
|
||||
|
||||
|
@ -50,7 +51,7 @@ static void map_pageframe_to(u64 target, u64 physical,
|
|||
PDT = (u64 *)memm_entry_get_address(pdpte);
|
||||
else
|
||||
{
|
||||
PDT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE);
|
||||
PDT = memm_allcate_pagetable();
|
||||
map_pagemap(PDT);
|
||||
memset(PDT, 0, MEMM_PAGE_SIZE);
|
||||
|
||||
|
@ -78,7 +79,7 @@ static void map_pageframe_to(u64 target, u64 physical,
|
|||
PT = (u64 *)memm_entry_get_address(pde);
|
||||
else
|
||||
{
|
||||
PT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE);
|
||||
PT = memm_allcate_pagetable();
|
||||
map_pagemap(PT);
|
||||
memset(PT, 0, MEMM_PAGE_SIZE);
|
||||
|
||||
|
@ -122,20 +123,6 @@ bool memm_map_pageframes_to(
|
|||
align = MEMM_4K_ALIGN_MASK + 1;
|
||||
}
|
||||
align /= MEMM_PAGE_SIZE;
|
||||
memory_manager_t *mm = memm_get_manager();
|
||||
switch (align)
|
||||
{
|
||||
case MEMM_PAGE_SIZE_4K:
|
||||
mm->platformed_page_counter.mapped_4k_page++;
|
||||
case MEMM_PAGE_SIZE_2M:
|
||||
mm->platformed_page_counter.mapped_2m_page++;
|
||||
case MEMM_PAGE_SIZE_1G:
|
||||
mm->platformed_page_counter.mapped_1g_page++;
|
||||
}
|
||||
for (usize i = physical / MEMM_PAGE_SIZE; i < physical / MEMM_PAGE_SIZE + align; i++)
|
||||
{
|
||||
bitmap_set(mm->page_map, i);
|
||||
}
|
||||
|
||||
map_pageframe_to(target, physical, user, write, align);
|
||||
|
||||
|
|
|
@ -17,54 +17,12 @@ memory_manager_t *memm_new(usize mem_size)
|
|||
usize kernel_initial_size = (usize)&kend;
|
||||
align_to(kernel_initial_size, MEMM_PAGE_SIZE);
|
||||
|
||||
// 配置分配器树
|
||||
allocator_t *allocator0 = memm_allocator_new(
|
||||
(void *)kernel_initial_size,
|
||||
memory_manager.alloc_only_memory - kernel_initial_size,
|
||||
memory_manager.alloc_only_memory - MEMM_PAGE_TABLE_AREA_MAX - kernel_initial_size,
|
||||
MEMM_RAW_ALLOCATOR, 0);
|
||||
|
||||
allocator_iterator_t *alcatr_ind = allocator0->allocate(
|
||||
&allocator0->allocator_instance, sizeof(allocator_iterator_t));
|
||||
|
||||
alcatr_ind->allocator = allocator0;
|
||||
alcatr_ind->left = nullptr;
|
||||
alcatr_ind->right = nullptr;
|
||||
|
||||
memory_manager.allocators = alcatr_ind;
|
||||
|
||||
// 配置页映射地图
|
||||
usize pmc_size = memory_manager.page_amount;
|
||||
align_to(pmc_size, 8);
|
||||
pmc_size /= 8;
|
||||
|
||||
memory_manager.page_map = allocator0->allocate(&allocator0->allocator_instance, pmc_size);
|
||||
memset(memory_manager.page_map, 0, pmc_size);
|
||||
memset(memory_manager.page_map, 0xff, MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE / 8);
|
||||
for (usize i = (MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE / 8) * (u8)8;
|
||||
i < MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE % 8; i++)
|
||||
{
|
||||
bitmap_set(memory_manager.page_map, i);
|
||||
}
|
||||
|
||||
// 配置分配器页地图
|
||||
memory_manager.allocator_map =
|
||||
allocator0->allocate(&allocator0->allocator_instance, pmc_size);
|
||||
memset(memory_manager.allocator_map, 0, pmc_size);
|
||||
for (usize i = kernel_initial_size / MEMM_PAGE_SIZE;
|
||||
i < MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE;
|
||||
i += MEMM_PAGE_SIZE)
|
||||
{
|
||||
bitmap_set(memory_manager.allocator_map, i);
|
||||
}
|
||||
|
||||
// 分配器释放页地图
|
||||
memory_manager.destructed_allocator_map =
|
||||
allocator0->allocate(&allocator0->allocator_instance, pmc_size);
|
||||
memset(memory_manager.destructed_allocator_map, 0, pmc_size);
|
||||
|
||||
// 配置空闲页线段搜索表
|
||||
memory_manager.available_pages_table = lst_new(0, memory_manager.page_amount);
|
||||
lst_remove(memory_manager.available_pages_table, 0, MEMM_ALLOC_ONLY_MEMORY / MEMM_PAGE_SIZE, false);
|
||||
memory_manager.kernel_base_allocator = allocator0;
|
||||
|
||||
return &memory_manager;
|
||||
}
|
||||
|
@ -102,129 +60,15 @@ void memm_allocator_destruct(allocator_t *allocator)
|
|||
KERNEL_TODO();
|
||||
}
|
||||
|
||||
void *memm_find_and_allocate(allocator_iterator_t *allocator_ind, usize size, usize pid, allocator_t **writeback)
|
||||
{
|
||||
void *ptr;
|
||||
allocator_t *allocator = allocator_ind->allocator;
|
||||
if (allocator->pid == pid && allocator->full == false)
|
||||
{ // 尝试用本节点分配
|
||||
if ((ptr = allocator->allocate(&allocator->allocator_instance, size)) != nullptr)
|
||||
{
|
||||
*writeback = allocator;
|
||||
return ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((ptr = allocator->allocate(&allocator->allocator_instance, 0)) == nullptr)
|
||||
allocator->full = true;
|
||||
}
|
||||
}
|
||||
if (allocator_ind->left != nullptr)
|
||||
{ // 尝试用左子树分配
|
||||
ptr = memm_find_and_allocate(allocator_ind->left, size, pid, writeback);
|
||||
if (ptr != nullptr)
|
||||
return ptr;
|
||||
}
|
||||
if (allocator_ind->right != nullptr)
|
||||
{ // 尝试用右子树分配
|
||||
ptr = memm_find_and_allocate(allocator_ind->right, size, pid, writeback);
|
||||
if (ptr != nullptr)
|
||||
return ptr;
|
||||
}
|
||||
// 都不行就只能返回nullptr
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void insert_allocator(allocator_iterator_t *iter, allocator_iterator_t *inserter)
|
||||
{
|
||||
if (inserter->allocator < iter->allocator)
|
||||
{
|
||||
if (iter->left == nullptr)
|
||||
{
|
||||
iter->left = inserter;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
insert_allocator(iter->left, inserter);
|
||||
}
|
||||
}
|
||||
else if (inserter->allocator > iter->allocator)
|
||||
{
|
||||
if (iter->right == nullptr)
|
||||
{
|
||||
iter->right = inserter;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
insert_allocator(iter->right, inserter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *memm_allocate(usize size, usize pid)
|
||||
{
|
||||
usize orgsize = size;
|
||||
// 从分配器树中分配内存
|
||||
allocator_t *allocator;
|
||||
void *ptr = memm_find_and_allocate(memory_manager.allocators, size, pid, &allocator);
|
||||
if (ptr != nullptr)
|
||||
goto after_allocation;
|
||||
|
||||
// 分配器树中没有可分配的内存
|
||||
size += sizeof(allocator_t) + MEMM_PAGE_SIZE;
|
||||
align_to(size, MEMM_PAGE_SIZE);
|
||||
size /= MEMM_PAGE_SIZE;
|
||||
usize allocator_start = find_fitable_pages(size);
|
||||
if (allocator_start == 0)
|
||||
return nullptr; // 内存中已经没有可分配的页了
|
||||
for (usize i = allocator_start; i < allocator_start + size; i++)
|
||||
{
|
||||
bitmap_set(memory_manager.allocator_map, i);
|
||||
}
|
||||
memm_map_pageframes_to(
|
||||
allocator_start * MEMM_PAGE_SIZE, allocator_start * MEMM_PAGE_SIZE,
|
||||
size * MEMM_PAGE_SIZE,
|
||||
false, // 用户空间标志
|
||||
true // 写权限
|
||||
);
|
||||
|
||||
// 在新映射的页中创建一个分配器
|
||||
// TODO 在用户态可能需要实现一个效率更高的分配器
|
||||
allocator_t *new_allocator =
|
||||
memm_allocator_new((void *)(allocator_start * MEMM_PAGE_SIZE), size * MEMM_PAGE_SIZE,
|
||||
MEMM_RAW_ALLOCATOR, pid);
|
||||
allocator = new_allocator;
|
||||
|
||||
allocator_iterator_t *allind = memm_kernel_allocate(sizeof(allocator_iterator_t));
|
||||
allind->allocator = new_allocator;
|
||||
allind->left = nullptr;
|
||||
allind->right = nullptr;
|
||||
insert_allocator(memory_manager.allocators, allind);
|
||||
ptr = new_allocator->allocate(&new_allocator->allocator_instance, orgsize);
|
||||
|
||||
after_allocation:
|
||||
if (ptr != nullptr)
|
||||
memm_addr_set_allocator(ptr, allocator);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *memm_kernel_allocate(usize size)
|
||||
{
|
||||
return memm_allocate(size, 0);
|
||||
}
|
||||
|
||||
void *memm_user_allocate(usize size, usize pid)
|
||||
{
|
||||
void *res = memm_allocate(size, pid);
|
||||
// TODO 将内存空间映射到用户空间
|
||||
return res;
|
||||
allocator_t *allocator = memory_manager.kernel_base_allocator;
|
||||
return allocator->allocate(allocator->allocator_instance, size);
|
||||
}
|
||||
|
||||
void memm_free(void *mem)
|
||||
{
|
||||
allocator_t *allocator = memm_addr_get_allocator(mem);
|
||||
allocator_t *allocator = memory_manager.kernel_base_allocator;
|
||||
if (allocator->magic != MEMM_ALLOCATOR_MAGIC)
|
||||
return;
|
||||
if (is_user_address((u64)mem))
|
||||
|
@ -236,23 +80,15 @@ void memm_free(void *mem)
|
|||
allocator->full = false;
|
||||
}
|
||||
|
||||
usize find_fitable_pages(usize page_count)
|
||||
void *memm_allcate_pagetable()
|
||||
{
|
||||
usize res = 0;
|
||||
lst_iterator_t *iter = memory_manager.available_pages_table;
|
||||
do
|
||||
if (memory_manager.page_table_area < MEMM_PAGE_TABLE_AREA_MAX)
|
||||
{
|
||||
if (iter->line.right - iter->line.left > page_count)
|
||||
{
|
||||
res = iter->line.left;
|
||||
lst_remove(iter, res, res + page_count, false);
|
||||
for (usize i = res; i < res + page_count; i++)
|
||||
{
|
||||
bitmap_set(memory_manager.page_map, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while ((iter = lst_next(iter)) != nullptr);
|
||||
memory_manager.mapped_page_amount += page_count;
|
||||
return res;
|
||||
memory_manager.page_table_area += MEMM_PAGE_TABLE_SIZE;
|
||||
return memory_manager.alloc_only_memory - memory_manager.page_table_area;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue