重构C语言部分的内存分配器

This commit is contained in:
pointer-to-bios 2024-04-06 04:07:32 +08:00
parent b0b790fab8
commit 00d655c468
6 changed files with 30 additions and 296 deletions

View File

@ -2,6 +2,7 @@
name = "metaverse" name = "metaverse"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
crate-type = ["staticlib"]
# 此Cargo.toml仅用于rust-analyzer识别rust部分的代码 # 此Cargo.toml仅用于rust-analyzer识别rust部分的代码
# 不应使用cargo编译 # 不应使用cargo编译

View File

@ -29,6 +29,8 @@
*/ */
#define MEMM_PAGE_SIZE 4096 #define MEMM_PAGE_SIZE 4096
#define MEMM_PAGE_TABLE_SIZE 4096
typedef enum __memm_page_size typedef enum __memm_page_size
{ {
MEMM_PAGE_SIZE_4K = 1, // 1个4KB页大小 MEMM_PAGE_SIZE_4K = 1, // 1个4KB页大小

View File

@ -24,11 +24,13 @@
/** /**
* @name MEMM_ALLOC_ONLY_MEMORY * @name MEMM_ALLOC_ONLY_MEMORY
* *
* `128MB``0`\~`MEMM_ALLOC_ONLY_MEMORY` * `64MB``0`\~`MEMM_ALLOC_ONLY_MEMORY`
* *
* **1MB以内低地址****** * **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 * @name memm_allocate_t, memm_free_t
@ -126,10 +128,6 @@ typedef struct __allocator_t
// 调用分配器的`free`方法时设为`false`。 // 调用分配器的`free`方法时设为`false`。
bool full; bool full;
// 进程标志服表示此分配器所属的进程为0代表属于内核。
usize pid;
// 若分配器不属于内核,此成员储存此分配器的用户空间地址。
void *userspace;
// 分配器类型。在目录`include/kernel/memm/allocator`中对每个分配器分别定义一个唯一值。 // 分配器类型。在目录`include/kernel/memm/allocator`中对每个分配器分别定义一个唯一值。
usize type; usize type;
usize size; usize size;
@ -144,75 +142,23 @@ typedef struct __allocator_t
u64 allocator_instance[0]; u64 allocator_instance[0];
} allocator_t; } allocator_t;
typedef struct __allocator_iterator_t
{
allocator_t *allocator;
struct __allocator_iterator_t *left, *right;
} allocator_iterator_t;
/** /**
* @name * @name
* *
* @internal alloc_only_memory * @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表示对应的最小页是否曾经被分配器控制并且现在控制这个页的分配器已经释放
*
* 1bit位对应的最小页可以直接************
*
* @internal available_pages_table
*
* 线
*
* @internal allocators
*
*
*/ */
typedef struct __mem_manager_t typedef struct __mem_manager_t
{ {
usize memory_size; usize memory_size;
usize page_amount; usize page_amount;
// 在进入内核主程序之前,有些不在内核中的虚拟内存空间已经被页表映射,这部分内存不可以再映射到物理页框
usize alloc_only_memory; usize alloc_only_memory;
// 已经映射的页数量。若不是最小的页会被视作多个最小页计数。 allocator_t *kernel_base_allocator;
usize mapped_page_amount;
memm_page_counter platformed_page_counter;
// 页地图。每个bit都表示这个页是否被映射。 usize page_table_area;
u8 *page_map;
// 分配器页地图。每个bit表示这个页是否被内存分配器控制。
u8 *allocator_map;
// 释放的分配器页地图。每个bit表示这个页是否曾经被内存分配器控制且现在被释放。
// 值为1的bit位对应的最小页可以直接**取消映射**、**重新构造一个分配器**、**加载可执行程序**等。
u8 *destructed_allocator_map;
// 空闲页线段搜索表
lst_iterator_t *available_pages_table;
// 分配器二叉树
allocator_iterator_t *allocators;
} memory_manager_t; } 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); 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 * @name memm_kernel_allocate
* *
@ -289,17 +218,6 @@ void *memm_allocate(usize size, usize pid);
*/ */
void *memm_kernel_allocate(usize size); 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 * @name memm_free
* *
@ -311,14 +229,6 @@ void *memm_user_allocate(usize size, usize pid);
*/ */
void memm_free(void *mem); void memm_free(void *mem);
/** void *memm_allcate_pagetable();
* @name find_fitable_pages
*
* ```c
* usize find_fitable_pages(usize page_count);
* ```
*
*/
usize find_fitable_pages(usize page_count);
#endif #endif

View File

@ -10,8 +10,6 @@ typedef struct __raw_allocator_cell
{ {
usize capacity; // 是content的长度 usize capacity; // 是content的长度
usize length; // 是实际使用的长度 usize length; // 是实际使用的长度
allocator_t *allocator; // 所在的分配器
usize reserved;
u8 content[0]; u8 content[0];
} raw_allocator_cell; } raw_allocator_cell;
#define raw_allocator_next_cell(cell) (raw_allocator_cell *)((void *)((cell)->content) + (cell)->capacity) #define raw_allocator_next_cell(cell) (raw_allocator_cell *)((void *)((cell)->content) + (cell)->capacity)

View File

@ -9,7 +9,8 @@
map_pageframe_to((u64)addr, (u64)addr, false, true, MEMM_PAGE_SIZE_4K); map_pageframe_to((u64)addr, (u64)addr, false, true, MEMM_PAGE_SIZE_4K);
// 这里的physical必须保证根据ps对齐 // 这里的physical必须保证根据ps对齐
static void map_pageframe_to(u64 target, u64 physical, static void map_pageframe_to(
u64 target, u64 physical,
bool user, bool write, memm_page_size ps) bool user, bool write, memm_page_size ps)
{ {
if (!is_cannonical(target)) if (!is_cannonical(target))
@ -22,7 +23,7 @@ static void map_pageframe_to(u64 target, u64 physical,
PDPT = (u64 *)memm_entry_get_address(pml4e); PDPT = (u64 *)memm_entry_get_address(pml4e);
else else
{ {
PDPT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE); PDPT = memm_allcate_pagetable();
map_pagemap(PDPT); map_pagemap(PDPT);
memset(PDPT, 0, MEMM_PAGE_SIZE); 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); PDT = (u64 *)memm_entry_get_address(pdpte);
else else
{ {
PDT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE); PDT = memm_allcate_pagetable();
map_pagemap(PDT); map_pagemap(PDT);
memset(PDT, 0, MEMM_PAGE_SIZE); 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); PT = (u64 *)memm_entry_get_address(pde);
else else
{ {
PT = (u64 *)(find_fitable_pages(1) * MEMM_PAGE_SIZE); PT = memm_allcate_pagetable();
map_pagemap(PT); map_pagemap(PT);
memset(PT, 0, MEMM_PAGE_SIZE); memset(PT, 0, MEMM_PAGE_SIZE);
@ -122,20 +123,6 @@ bool memm_map_pageframes_to(
align = MEMM_4K_ALIGN_MASK + 1; align = MEMM_4K_ALIGN_MASK + 1;
} }
align /= MEMM_PAGE_SIZE; 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); map_pageframe_to(target, physical, user, write, align);

View File

@ -17,54 +17,12 @@ memory_manager_t *memm_new(usize mem_size)
usize kernel_initial_size = (usize)&kend; usize kernel_initial_size = (usize)&kend;
align_to(kernel_initial_size, MEMM_PAGE_SIZE); align_to(kernel_initial_size, MEMM_PAGE_SIZE);
// 配置分配器树
allocator_t *allocator0 = memm_allocator_new( allocator_t *allocator0 = memm_allocator_new(
(void *)kernel_initial_size, (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); MEMM_RAW_ALLOCATOR, 0);
allocator_iterator_t *alcatr_ind = allocator0->allocate( memory_manager.kernel_base_allocator = allocator0;
&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);
return &memory_manager; return &memory_manager;
} }
@ -102,129 +60,15 @@ void memm_allocator_destruct(allocator_t *allocator)
KERNEL_TODO(); 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) void *memm_kernel_allocate(usize size)
{ {
return memm_allocate(size, 0); allocator_t *allocator = memory_manager.kernel_base_allocator;
} return allocator->allocate(allocator->allocator_instance, size);
void *memm_user_allocate(usize size, usize pid)
{
void *res = memm_allocate(size, pid);
// TODO 将内存空间映射到用户空间
return res;
} }
void memm_free(void *mem) 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) if (allocator->magic != MEMM_ALLOCATOR_MAGIC)
return; return;
if (is_user_address((u64)mem)) if (is_user_address((u64)mem))
@ -236,23 +80,15 @@ void memm_free(void *mem)
allocator->full = false; allocator->full = false;
} }
usize find_fitable_pages(usize page_count) void *memm_allcate_pagetable()
{ {
usize res = 0; if (memory_manager.page_table_area < MEMM_PAGE_TABLE_AREA_MAX)
lst_iterator_t *iter = memory_manager.available_pages_table;
do
{ {
if (iter->line.right - iter->line.left > page_count) memory_manager.page_table_area += MEMM_PAGE_TABLE_SIZE;
{ return memory_manager.alloc_only_memory - memory_manager.page_table_area;
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; else
{
// TODO
} }
} while ((iter = lst_next(iter)) != nullptr);
memory_manager.mapped_page_amount += page_count;
return res;
} }