练习1
实现 first-fit 连续物理内存分配算法
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) {
if (page->property > n) {
struct Page *p = page + n;
p->property = page->property - n;
list_add(&(page->page_link), &(p->page_link));
}
int i=0;
for (; i<n; i++) {
ClearPageProperty(page + i);
}
page->property = 0;
list_del(&(page->page_link));
nr_free -= n;
}
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; // Clear the status of page frame
set_page_ref(p, 0); // Set the reference count of page frame to 0
}
base->property = n; // Set the count of free page frames
SetPageProperty(base); // Indicate that the page is head page of a free memmory block
list_entry_t *le = list_next(&free_list);
// Try to merge blocks at lower or higher addresses
while (le != &free_list) {
p = le2page(le, page_link);
le = list_next(le);
if (base + base->property == p) { // Merge block at higher address
base->property += p->property;
ClearPageProperty(p); // Higher block is not the head of free block yet, so we should remove it's head flag and remove it from the list of free pages
list_del(&(p->page_link));
}
else if (p + p->property == base) { // Merge block at lower address
p->property += base->property;
ClearPageProperty(base);
base = p; // Change the current block's address
list_del(&(p->page_link));
}
}
nr_free += n; // Increase the total count of free pages
// Add the block at correct position
le = list_next(&free_list);
while (le != &free_list) {
p = le2page(le, page_link);
if (base + base->property < p) { // Find the correct position
break;
}
le = list_next(le);
}
list_add_before(le, &(base->page_link));
}
练习2
实现寻找虚拟地址对应的页表项
pte_t *
get_pte(pde_t *pgdir, uintptr_t la, bool create) {
// Get page directory index.
unsigned int pdx = PDX(la);
// Find the address of page entry in page directory.
pde_t *ppde = &pgdir[pdx];
// Check if page is present or not.
if (!(*ppde & PTE_P))
{
struct Page *ppage;
if (!create || (ppage = alloc_page()) == NULL )
{
return NULL;
}
set_page_ref(ppage, 1);
uintptr_t pa = page2pa(ppage);
memset(page2kva(ppage), 0, PGSIZE);
*ppde = pa | PTE_P | PTE_U | PTE_W;
}
return &((pte_t *)KADDR(PDE_ADDR(*ppde)))[PTX(la)];
}
练习3
释放某虚地址所在的页并取消对应二级页表项的映射
static inline void
page_remove_pte(pde_t *pgdir, uintptr_t la, pte_t *ptep) {
// check if the page table entry is not present
if (!(*ptep & PTE_P))
{
return;
}
// find corresponding page to pte
struct Page *page = pte2page(*ptep);
// decrease page reference
page_ref_dec(page);
// if the reference of page is 0, then this page shoule be free
if (page->ref == 0)
{
free_page(page);
}
// clear 2nd level page table entry
*ptep = 0;
// flush TLB
tlb_invalidate(pgdir, la);
}