自己动手写操作系统(六)
程序员文章站
2024-03-24 11:51:04
...
今天开始进入内存管理的编写。按照顺序,我们首先要实现的是kmalloc。在arale os中我们用coalition_allocator来进行kmalloc对应的内存管理。实际上,coalition_allocator的内存管理方法是参照了buddy来的。有兴趣的同学可以在网上找到很多关于buddy的内存管理文章,这里就不在多说了。
我们先来看几个比较关键的结构体:
1.已分配内存头:
typedef struct pmm_stamp
{
int type;
union
{
mm_page page;
core_mem_cache_content cache_content;
};
}pmm_stamp;
这个结构体实际上是用来标记了分配出去的内存类型/相关的page信息。每次分配内存时,我们都会多分配一些内存来保存这个信息。方便之后的内存释放和管理。下图就是实际的内存非配内容:
|pmm_stamp|memory
|
|
这里是返回给上层的地址(addr),我们可以通过(pmm_stamp *)(addr - sizeof(pmm_stamp))就可以获取当前分配出内存的所有信息。
其中type主要有下面几类:
enum PMM_TYPE {
PMM_TYPE_NORMAL = 0,
PMM_TYPE_PMEM,
PMM_TYPE_CACHE
};
PMM_TYPE_NORMAL:正常的物理内存,它的头长度就是sizeof(pmm_stamp)
PMM_TYPE_PMEM:4K对齐物理内存,这个主要是用来给PGD用的,因为注册PGD的内存必须是4K对齐,所以它的起始地址也必须是4K对齐。如果使用NORMAL,有可能出现未4K对齐的情况。
PMM_TYPE_CACHE:小内存使用。
2.page信息
typedef struct mm_page
{
struct list_head ll;
addr_t start_pa;
uint32_t size;
int type;
core_mem_cache_content *cache;
}mm_page;
ll:主要用来插入free/used队列
start_pa:记录物理地址
size:记录内存大小,方便free
cache:之后用来做小内存的slab管理
3.memory zone信息
typedef struct mm_zone
{
addr_t start_pa;
addr_t end_pa;
//use the follow three param to do kswap.
uint32_t pages_low;
uint32_t pages_high;
uint32_t pages_mid;
//free pages
uint32_t total_free_pages;
zone_area nr_area[ZONE_FREE_MAX_ORDER]; //4K,8K,16K
void (*alloctor_init)(addr_t start_address,uint32_t size);
void* (*alloctor_get_memory)(uint32_t size);
int (*alloctor_free)(addr_t address);
void* (*alloctor_pmem)(uint32_t size);
void (*alloctor_pmem_free)(addr_t address);
}mm_zone;
kmalloc主要是针对normal zone做的内存分配。所以我们用nr_area[]来管理4K/8K/16K/32K等等。而zone_area其实就是一个包含2个list的struct
typedef struct zone_area
{
struct list_head free_page_list;
struct list_head used_page_list;
//uint32_t nr_free_pages; no use
}zone_area;
free_page_list:用来存放当前块对应的free 内存
user_page_list:用来存放当前块已分配的内存
内存关键的数据结构基本上就是上面这几个。接下来的处理就是用这些数据结构来管理物理内存。具体流程下篇继续。
arale os github:
https://github.com/wangsun1983/arale