页面分配算法
我们在default_pmm.c
定义了一个pmm_manager类型的结构体,并实现它的接口
// kern/mm/default_pmm.h
#ifndef __KERN_MM_DEFAULT_PMM_H__
#define __KERN_MM_DEFAULT_PMM_H__
#include <pmm.h>
extern const struct pmm_manager default_pmm_manager;
#endif /* ! __KERN_MM_DEFAULT_PMM_H__ */
较为关键的,是一开始如何初始化所有可用页面,以及如何分配和释放页面。这里实现了First Fit算法。
// kern/mm/default_pmm.c
free_area_t free_area;
#define free_list (free_area.free_list)
#define nr_free (free_area.nr_free)
static void
default_init(void) {
list_init(&free_list);
nr_free = 0;//nr_free可以理解为在这里可以使用的一个全局变量,记录可用的物理页面数
}
static void
default_init_memmap(struct Page *base, size_t n) {
assert(n > 0);
struct Page *p = base;
for (; p != base + n; p ++) {
assert(PageReserved(p));
p->flags = p->property = 0;
set_page_ref(p, 0);
}
base->property = n;
SetPageProperty(base);
nr_free += n;
if (list_empty(&free_list)) {
list_add(&free_list, &(base->page_link));
} else {
list_entry_t* le = &free_list;
while ((le = list_next(le)) != &free_list) {
struct Page* page = le2page(le, page_link);
if (base < page) {
list_add_before(le, &(base->page_link));
break;
} else if (list_next(le) == &free_list) {
list_add(le, &(base->page_link));
}
}
}
}
static struct Page *
default_alloc_pages(size_t n) {
assert(n > 0);
if (n > nr_free) {
return NULL;
}
struct Page *page = NULL;
list_entry_t *le = &free_list;
while ((le = list_next(le)) != &free_list) {
struct Page *p = le2page(le, page_link);
if (p->property >= n) {
page = p;
break;
}
}
if (page != NULL) {
list_entry_t* prev = list_prev(&(page->page_link));
list_del(&(page->page_link));
if (page->property > n) {
struct Page *p = page + n;
p->property = page->property - n;
SetPageProperty(p);
list_add(prev, &(p->page_link));
}
nr_free -= n;
ClearPageProperty(page);
}
return page;
}
static void
default_free_pages(struct Page *base, size_t n) {
assert(n > 0);
struct Page *p = base;
for (; p != base + n; p ++) {
assert(!PageReserved(p) && !PageProperty(p));
p->flags = 0;
set_page_ref(p, 0);
}
base->property = n;
SetPageProperty(base);
nr_free += n;
if (list_empty(&free_list)) {
list_add(&free_list, &(base->page_link));
} else {
list_entry_t* le = &free_list;
while ((le = list_next(le)) != &free_list) {
struct Page* page = le2page(le, page_link);
if (base < page) {
list_add_before(le, &(base->page_link));
break;
} else if (list_next(le) == &free_list) {
list_add(le, &(base->page_link));
}
}
}
list_entry_t* le = list_prev(&(base->page_link));
if (le != &free_list) {
p = le2page(le, page_link);
if (p + p->property == base) {
p->property += base->property;
ClearPageProperty(base);
list_del(&(base->page_link));
base = p;
}
}
le = list_next(&(base->page_link));
if (le != &free_list) {
p = le2page(le, page_link);
if (base + base->property == p) {
base->property += p->property;
ClearPageProperty(p);
list_del(&(p->page_link));
}
}
}
const struct pmm_manager default_pmm_manager = {
.name = "default_pmm_manager",
.init = default_init,
.init_memmap = default_init_memmap,
.alloc_pages = default_alloc_pages,
.free_pages = default_free_pages,
.nr_free_pages = default_nr_free_pages,
.check = default_check,
};
目前为止的代码可以在这里找到,遇到困难可以参考。
最后更新于