ucore lab2 物理内存管理

ucore lab2 物理内存管理

练习1:实现 first-fit 连续物理内存分配算法(需要编程)
default_init(void)
初始化一个链表
default_init_memmap(struct Page *base, size_t n)

就是将空闲内存挂在空闲链表上,我看答案是一个一个都挂上去了,然后将开头设置包含后面的信息,而我是直接一把他们变成一整块挂在链表上

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));
}
default_alloc_pages(size_t n)

分配内存的时候,遍历空闲链表,遇到第一个可以用的就取下来,如果还比较大就切一下

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;
}
default_free_pages(struct Page *base, size_t n)

释放时,也是先找位置,我是直接找到该位置后面的一个位置,然后循环向前看能否合并,不能合并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);
    }

总结:大致上就是链表的基本操作,不过要注意,分配释放时的标志信息要改写,感觉我的不太对在某些时候,有时候遍历输出的时候遍历链表就死循环了,但是看起来分配和回收时不影响,有些神奇

练习2:实现寻找虚拟地址对应的页表项(需要编程)
get_pte(pde_t *pgdir, uintptr_t la, bool create)

参数定义: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
    }

这个地址就很晕哎

练习3:释放某虚地址所在的页并取消对应二级页表项的映射(需要编程)
page_remove_pte(pde_t *pgdir, uintptr_t la, pte_t *ptep)
    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.
 *
 * */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DyingLive

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值