初始化一个链表
就是将空闲内存挂在空闲链表上,我看答案是一个一个都挂上去了,然后将开头设置包含后面的信息,而我是直接一把他们变成一整块挂在链表上
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 = PG_property;
p->property = 0;
set_page_ref(p, 0);
SetPageProperty(p);
}
list_add_before(&free_list, &(base->page_link));
base->property = n;
nr_free += n;
// list_add(&free_list, &(base->page_link));
}
分配内存的时候,遍历空闲链表,遇到第一个可以用的就取下来,如果还比较大就切一下
static struct Page *
default_alloc_pages(size_t n)
{
#ifdef $DEBUG
cprintf("\n!!!!!!!!!!!memory alloc :!!!!!!!!!!!!!!!!!\n");
#endif
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)
{
SetPageReserved(page);
ClearPageProperty(page);
if (page->property > n)//比较大时先切下来放到空闲列表上然后在删,不然找不到位置了就
{
struct Page *p = page + n;
p->property = page->property - n;
list_add(&page->page_link, &(p->page_link));
}
list_del(&(page->page_link));
nr_free -= n;
ClearPageProperty(page);
}
#ifdef DEBUG
le = &free_list;
while((le = list_next(le)) != &free_list)
{
page = le2page(le , page_link);
cprintf("memory page address = %p ,property = %ld\n" , page , page->property);
}
#endif
return page;
}
释放时,也是先找位置,我是直接找到该位置后面的一个位置,然后循环向前看能否合并,不能合并break就行
list_entry_t *le = &free_list;
do{//找位置
le = list_next(le);
#ifdef $DEBUG
cprintf("...loop location base->link = %p le = %p \n", &base->page_link, le);
#endif
} while (&base->page_link > le && le != &free_list);// search location
p = le2page(le, page_link);
le = list_prev(le);
if (base + base->property == p)//看一下后面的能否合并
{
base->property += p->property;
ClearPageProperty(p);
list_del(&(p->page_link));
}
while (le != &free_list)//看一下前面的能否合并
{
p = le2page(le, page_link);
if (p + p->property == base)
{
p->property += base->property;
ClearPageProperty(base);
base = p;
list_del(&(p->page_link));
}
else
{
break;
}
le = list_prev(le);
}
总结:大致上就是链表的基本操作,不过要注意,分配释放时的标志信息要改写,感觉我的不太对在某些时候,有时候遍历输出的时候遍历链表就死循环了,但是看起来分配和回收时不影响,有些神奇
参数定义:pgdir页目录起始地址 , la是线性地址 ,create是否创造
// get_pte - get pte and return the kernel virtual address of this pte for la
// - if the PT contains this pte didn't exist, alloc a page for PT
// parameter:
// pgdir: the kernel virtual base address of PDT
// la: the linear address need to map
// create: a logical value to decide if alloc a page for PT
// return vaule: the kernel virtual address of this pte
首先要获取页目录对应的表项配合la的偏移计算
pde_t *pdep = &pgdir[PDX(la)]; // (1) find page directory entry
然后显看是否存在,存在就直接返回对应配合la计算出来的页表项
return &((pte_t *)KADDR(PDE_ADDR(*pdep)))[PTX(la)]; // (8) return page table entry
不存在则要看需不需要创造
if (!(*pdep & PTE_P)) // (2) check if entry is not present
{
struct Page *page;
if (!create || (page = alloc_page()) == NULL)
{ // (3) check if creating is needed, then alloc page for page table
return NULL; // CAUTION: this page is used for page table, not for common data page
}
set_page_ref(page, 1); // (4) set page reference
uintptr_t pa = page2pa(page); // (5) get linear address of page
memset(KADDR(pa), 0, PGSIZE); // (6) clear page content using memset
*pdep = pa | PTE_P | PTE_W | PTE_U; // (7) set page directory entry's permission
}
这个地址就很晕哎
if (*ptep & PTE_P)
{
struct Page *page = pte2page(*ptep); //(2) find corresponding page to pte
if (page_ref_dec(page) == 0) //(3) decrease page reference
{
free_page(page); //(4) and free this page when page reference reachs 0
}
*ptep = 0; //(5) clear second page table entry
tlb_invalidate(pgdir, la); //(6) flush tlb
}
注释太全了,直接写了就行
注:
/* *
* Virtual memory map: Permissions
* kernel/user
*
* 4G ------------------> +---------------------------------+
* | |
* | Empty Memory (*) |
* | |
* +---------------------------------+ 0xFB000000
* | Cur. Page Table (Kern, RW) | RW/-- PTSIZE
* VPT -----------------> +---------------------------------+ 0xFAC00000
* | Invalid Memory (*) | --/--
* KERNTOP -------------> +---------------------------------+ 0xF8000000
* | |
* | Remapped Physical Memory | RW/-- KMEMSIZE
* | |
* KERNBASE ------------> +---------------------------------+ 0xC0000000
* | |
* | |
* | |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* (*) Note: The kernel ensures that "Invalid Memory" is *never* mapped.
* "Empty Memory" is normally unmapped, but user programs may map pages
* there if desired.
*
* */