new: 初步实现了mmio的伙伴系统

This commit is contained in:
fslongjin 2022-08-18 22:06:29 +08:00
parent 4950d43e65
commit 77633e2f19
9 changed files with 384 additions and 5 deletions

View File

@ -126,7 +126,8 @@
"mm-types.h": "c", "mm-types.h": "c",
"vfs.h": "c", "vfs.h": "c",
"current.h": "c", "current.h": "c",
"proc-types.h": "c" "proc-types.h": "c",
"traceback.h": "c"
}, },
"C_Cpp.errorSquiggles": "Enabled", "C_Cpp.errorSquiggles": "Enabled",
"esbonio.sphinx.confDir": "" "esbonio.sphinx.confDir": ""

View File

@ -2,7 +2,7 @@
CFLAGS += -I . CFLAGS += -I .
all:mm.o slab.o mm-stat.o vma.o mmap.o utils.o all:mm.o slab.o mm-stat.o vma.o mmap.o utils.o mmio.o mmio-buddy.o
mm.o: mm.c mm.o: mm.c
gcc $(CFLAGS) -c mm.c -o mm.o gcc $(CFLAGS) -c mm.c -o mm.o
@ -20,4 +20,10 @@ mmap.o: mmap.c
gcc $(CFLAGS) -c mmap.c -o mmap.o gcc $(CFLAGS) -c mmap.c -o mmap.o
utils.o: utils.c utils.o: utils.c
gcc $(CFLAGS) -c utils.c -o utils.o gcc $(CFLAGS) -c utils.c -o utils.o
mmio.o: mmio.c
gcc $(CFLAGS) -c mmio.c -o mmio.o
mmio-buddy.o: mmio-buddy.c
gcc $(CFLAGS) -c mmio-buddy.c -o mmio-buddy.o

View File

@ -11,6 +11,7 @@
uint64_t mm_Total_Memory = 0; uint64_t mm_Total_Memory = 0;
uint64_t mm_total_2M_pages = 0; uint64_t mm_total_2M_pages = 0;
struct mm_struct initial_mm = {0};
struct memory_desc memory_management_struct = {{0}, 0}; struct memory_desc memory_management_struct = {{0}, 0};

View File

@ -13,6 +13,8 @@
#define PAGE_OFFSET (0xffff800000000000UL) #define PAGE_OFFSET (0xffff800000000000UL)
#define KERNEL_BASE_LINEAR_ADDR (0xffff800000000000UL) #define KERNEL_BASE_LINEAR_ADDR (0xffff800000000000UL)
#define USER_MAX_LINEAR_ADDR 0x00007fffffffffffUL #define USER_MAX_LINEAR_ADDR 0x00007fffffffffffUL
#define MMIO_BASE (0xffffa10000000000UL)
#define MMIO_TOP (0xffffa20000000000UL)
#define PAGE_4K_SHIFT 12 #define PAGE_4K_SHIFT 12
#define PAGE_2M_SHIFT 21 #define PAGE_2M_SHIFT 21

260
kernel/mm/mmio-buddy.c Normal file
View File

@ -0,0 +1,260 @@
#include "mmio-buddy.h"
#include <mm/slab.h>
/**
* @brief
*
*/
#define __exp2index(exp) (exp - 12)
/**
* @brief
*
*/
#define buddy_block_vaddr(vaddr, exp) (vaddr ^ (1UL << exp))
static struct mmio_buddy_mem_pool __mmio_pool; // mmio buddy内存池
/**
* @brief
*
* @param index
* @param region
* @return __always_inline
*/
static __always_inline void __buddy_add_region_obj(int index, struct __mmio_buddy_addr_region *region)
{
struct __mmio_free_region_list *lst = &__mmio_pool.free_regions[index];
list_init(&region->list);
list_append(&lst->list_head, &region->list);
++lst->num_free;
}
/**
* @brief
*
* @param vaddr
* @return
*/
static __always_inline struct __mmio_buddy_addr_region *__mmio_buddy_create_region(uint64_t vaddr)
{
// 申请内存块的空间
struct __mmio_buddy_addr_region *region = (struct __mmio_buddy_addr_region *)kzalloc(sizeof(struct __mmio_buddy_addr_region), 0);
list_init(&region->list);
region->vaddr = vaddr;
return region;
}
/**
* @brief address region结构体
*
* @param region
*/
static __always_inline void __release_addr_region(struct __mmio_buddy_addr_region *region)
{
kfree(region);
}
/**
* @brief (2^exp)
*
* @param region
* @param exp
*/
static __always_inline void __buddy_split(struct __mmio_buddy_addr_region *region, int exp)
{
// 计算分裂出来的新的伙伴块的地址
struct __mmio_buddy_addr_region *new_region = __mmio_buddy_create_region(buddy_block_vaddr(region->vaddr, exp - 1));
__buddy_add_region_obj(__exp2index(exp - 1), region);
__buddy_add_region_obj(__exp2index(exp - 1), new_region);
}
/**
* @brief
*
* @param x
* @param y
* @param exp xy大小的幂
* @return int
*/
static __always_inline int __buddy_merge_blocks(struct __mmio_buddy_addr_region *x, struct __mmio_buddy_addr_region *y, int exp)
{
// 判断这两个是否是一对伙伴
if (unlikely(x->vaddr != buddy_block_vaddr(y->vaddr, exp))) // 不是一对伙伴
return -EINVAL;
// === 是一对伙伴,将他们合并
// __mmio_pool.free_regions[__exp2index(exp)].num_free -=2;
// 释放y
__release_addr_region(y);
// 插入x
__buddy_add_region_obj(__exp2index(exp + 1), x);
return 0;
}
/**
* @brief ,
*
* @param exp
* @return __always_inline struct*
*/
static __always_inline struct __mmio_buddy_addr_region *__buddy_pop_region(int exp)
{
if (unlikely(&__mmio_pool.free_regions[__exp2index(exp)].list_head))
return NULL;
struct __mmio_buddy_addr_region *r = container_of(list_next(&__mmio_pool.free_regions[__exp2index(exp)].list_head), struct __mmio_buddy_addr_region, list);
list_del(&r->list);
// 区域计数减1
--__mmio_pool.free_regions[__exp2index(exp)].num_free;
return r;
}
/**
* @brief
*
* @param x
* @param exp
* @return
*/
static __always_inline struct __mmio_buddy_addr_region *__find_buddy(struct __mmio_buddy_addr_region *x, int exp)
{
// 当前为空
if (unlikely(list_empty(&__mmio_pool.free_regions[__exp2index(exp)].list_head)))
return NULL;
// 遍历链表以寻找伙伴块
uint64_t buddy_vaddr = buddy_block_vaddr(x->vaddr, exp);
struct List *list = &__mmio_pool.free_regions[__exp2index(exp)].list_head;
do
{
list = list_next(list);
struct __mmio_buddy_addr_region *bd = container_of(list, struct __mmio_buddy_addr_region, list);
if (bd->vaddr == buddy_vaddr) // 找到了伙伴块
return bd;
} while (list_next(list) != &__mmio_pool.free_regions[__exp2index(exp)].list_head);
return NULL;
}
/**
* @brief (2^(exp+1))
*
* @param exp 2^exp
*/
static void __buddy_merge(int exp)
{
struct __mmio_free_region_list *free_list = &__mmio_pool.free_regions[__exp2index(exp)];
// 若链表为空
if (list_empty(&free_list->list_head))
return;
struct List *list = list_next(&free_list->list_head);
do
{
struct __mmio_buddy_addr_region *ptr = container_of(list, struct __mmio_buddy_addr_region, list);
// 寻找是否有伙伴块
struct __mmio_buddy_addr_region *bd = __find_buddy(ptr, exp);
// 一定要在merge之前执行,否则list就被重置了
list = list_next(list);
if (bd != NULL) // 找到伙伴块
{
free_list->num_free -= 2;
list_del(&ptr->list);
list_del(&bd->list);
__buddy_merge_blocks(ptr, bd, exp);
}
} while (list != &free_list->list_head);
}
/**
* @brief buddy中申请一块指定大小的内存区域
*
* @param exp (2^exp)
* @return struct __mmio_buddy_addr_region* NULL
*/
static struct __mmio_buddy_addr_region *__buddy_query_addr_region(int exp)
{
if (exp >= MMIO_BUDDY_MAX_EXP)
return NULL;
if (!list_empty(&__mmio_pool.free_regions[__exp2index(exp)].list_head))
goto has_block;
// 若没有符合要求的内存块,则先尝试分裂大的块
for (int cur_exp = exp; exp <= MMIO_BUDDY_MAX_EXP; ++cur_exp)
{
if (unlikely(list_empty(&__mmio_pool.free_regions[__exp2index(cur_exp)].list_head))) // 一直寻找到有空闲空间的链表
continue;
// 找到了,逐级向下split
for (int down_exp = cur_exp; down_exp > exp; --down_exp)
{
// 取出一块空闲区域
struct __mmio_buddy_addr_region *r = __buddy_pop_region(down_exp);
__buddy_split(r, down_exp);
}
break;
}
if (!list_empty(&__mmio_pool.free_regions[__exp2index(exp)].list_head))
goto has_block;
// 尝试合并小的伙伴块
for (int cur_exp = MMIO_BUDDY_MIN_EXP; cur_exp < exp; ++cur_exp)
__buddy_merge(cur_exp);
// 再次尝试获取符合要求的内存块若仍不成功则说明mmio空间耗尽
if (!list_empty(&__mmio_pool.free_regions[__exp2index(exp)].list_head))
goto has_block;
else
goto failed;
failed:;
return NULL;
has_block:; // 有可用的内存块,分配
return __buddy_pop_region(exp);
}
/**
* @brief buddy
*
* @param vaddr
* @param exp 2^exp
* @return int
*/
static __always_inline int __buddy_give_back(uint64_t vaddr, int exp)
{
// 确保内存对齐低位都要为0
if (vaddr & ((1UL << exp) - 1))
return -EINVAL;
struct __mmio_buddy_addr_region *region = __mmio_buddy_create_region(vaddr);
// 加入buddy
__buddy_add_region_obj(__exp2index(exp), region);
return 0;
}
/**
* @brief mmio的伙伴系统
*
*/
void mmio_buddy_init()
{
memset(&__mmio_pool, 0, sizeof(struct mmio_buddy_mem_pool));
spin_init(&__mmio_pool.op_lock);
// 初始化各个链表的头部
for (int i = 0; i < MMIO_BUDDY_REGION_COUNT; ++i)
{
list_init(&__mmio_pool.free_regions[i].list_head);
__mmio_pool.free_regions[i].num_free = 0;
}
// 创建一堆1GB的地址块
uint32_t cnt_1g_blocks = (MMIO_TOP - MMIO_BASE) / PAGE_1G_SIZE;
uint64_t vaddr_base = MMIO_BASE;
for (uint32_t i = 0; i < cnt_1g_blocks; ++i, vaddr_base += PAGE_1G_SIZE)
__buddy_give_back(vaddr_base, PAGE_1G_SHIFT);
}

51
kernel/mm/mmio-buddy.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include <common/sys/types.h>
#include <common/glib.h>
#include "mm-types.h"
#include "mm.h"
#define MMIO_BUDDY_MAX_EXP PAGE_1G_SHIFT
#define MMIO_BUDDY_MIN_EXP PAGE_4K_SHIFT
#define MMIO_BUDDY_REGION_COUNT (MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1)
/**
* @brief mmio伙伴系统内部的地址区域结构体
*
*/
struct __mmio_buddy_addr_region
{
struct List list;
uint64_t vaddr; // 该内存对象起始位置的虚拟地址
};
/**
* @brief
*
*/
struct __mmio_free_region_list
{
struct List list_head;
int64_t num_free; // 空闲页的数量
};
/**
* @brief buddy内存池
*
*/
struct mmio_buddy_mem_pool
{
uint64_t pool_start_addr; // 内存池的起始地址
uint64_t pool_size; // 内存池的内存空间总大小
spinlock_t op_lock; // 操作锁
/**
* @brief
* i个元素代表大小为2^(i+12)
*/
struct __mmio_free_region_list free_regions[MMIO_BUDDY_REGION_COUNT];
};
/**
* @brief mmio的伙伴系统
*
*/
void mmio_buddy_init();

34
kernel/mm/mmio.c Normal file
View File

@ -0,0 +1,34 @@
#include "mmio.h"
#include "mmio-buddy.h"
void mmio_init()
{
mmio_buddy_init();
}
/**
* @brief mmio区域vma绑定到initial_mm
*
* @param size mmio区域的大小
* @param length mmio区域长度
* @param vm_flags vma设置成的标志
* @param res_vaddr -
* @param res_length -
* @return int
*/
int mmio_create(uint32_t size, uint64_t length, vm_flags_t vm_flags, uint64_t * res_vaddr, uint64_t *res_length)
{
}
/**
* @brief mmio的映射并将地址空间归还到buddy中
*
* @param vaddr
* @param length
* @return int
*/
int mmio_release(uint64_t vaddr, uint64_t length)
{
}

25
kernel/mm/mmio.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "mm.h"
void mmio_init();
/**
* @brief mmio区域vma绑定到initial_mm
*
* @param size mmio区域的大小
* @param length mmio区域长度
* @param vm_flags vma设置成的标志
* @param res_vaddr -
* @param res_length -
* @return int
*/
int mmio_create(uint32_t size, uint64_t length, vm_flags_t vm_flags, uint64_t * res_vaddr, uint64_t *res_length);
/**
* @brief mmio的映射并将地址空间归还到buddy中
*
* @param vaddr
* @param length
* @return int
*/
int mmio_release(uint64_t vaddr, uint64_t length);

View File

@ -32,7 +32,7 @@ extern void system_call(void);
extern void kernel_thread_func(void); extern void kernel_thread_func(void);
ul _stack_start; // initial proc的栈基地址虚拟地址 ul _stack_start; // initial proc的栈基地址虚拟地址
struct mm_struct initial_mm = {0}; extern struct mm_struct initial_mm;
struct thread_struct initial_thread = struct thread_struct initial_thread =
{ {
.rbp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)), .rbp = (ul)(initial_proc_union.stack + STACK_SIZE / sizeof(ul)),
@ -458,7 +458,6 @@ exec_failed:;
ul initial_kernel_thread(ul arg) ul initial_kernel_thread(ul arg)
{ {
// kinfo("initial proc running...\targ:%#018lx", arg); // kinfo("initial proc running...\targ:%#018lx", arg);
fat32_init(); fat32_init();
usb_init(); usb_init();