labworkP02

实验报告

实验内容

uCore Lab 2:物理内存管理
(1) 编译运行 uCore Lab 2 的工程代码;
(2) 完成 uCore Lab 2 练习 1-3 的编程作业;
(3) 思考如何实现 uCore Lab 2 扩展练习 1-2。

实验环境

 Ubuntu 14.04(64位)

实验过程

练习1:实现 first-fit 连续物理内存分配算法(需要编程)

在实现first fit 内存分配算法的回收函数时,要考虑地址连续的空闲块之间的合并操作。提示:在建立空闲页块链表时,需要按照空闲页块起始地址来排序,形成一个有序的链表。可能会修改default_pmm.c中的default_init,default_init_memmap,default_alloc_pages, default_free_pages等相关函数。请仔细查看和理解default_pmm.c中的注释。

  1. 修改函数 default_init_memmap
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 = 0;
        SetPageProperty(p);
        p->property = 0;
        set_page_ref(p, 0);
        list_add_before(&free_list, &(p->page_link));
    }
    nr_free += n;
    //first block
    base->property = n;
}

设计实现过程:传入物理页基地址,和物理页的个数(个数必须大于0),然后对每一块物理页进行设置:先判断是否为保留页,如果不是,则进行下一步。将标志位清0,连续空页个数清0,然后将标志位设置为1,将引用此物理页的虚拟页的个数清0。然后再加入空闲链表。最后计算空闲页的个数,修改物理基地址页的property的个数为n。

  1. 修改函数 default_alloc_pages
static struct Page *
default_alloc_pages(size_t n) {
    assert(n > 0);
    if (n > nr_free) {
        return NULL;
    }
    list_entry_t *le, *len;
    le = &free_list;

    while((le=list_next(le)) != &free_list) {
      struct Page *p = le2page(le, page_link);
      if(p->property >= n){
        int i;
        for(i=0;i<n;i++){
          len = list_next(le);
          struct Page *pp = le2page(le, page_link);
          SetPageReserved(pp);
          ClearPageProperty(pp);
          list_del(le);
          le = len;
        }
        if(p->property>n){
          (le2page(le,page_link))->property = p->property - n;
        }
        ClearPageProperty(p);
        SetPageReserved(p);
        nr_free -= n;
        return p;
      }
    }
    return NULL;
}

设计实现过程:这个函数是用来分配空闲页的。首先判断空闲页的大小是否大于所需的页块大小。如果小于空闲页的大小。则遍历整个空闲链表。如果找到合适的空闲页,则重新设置标志位。然后从空闲链表中删除此页。如果当前空闲页的大小大于所需大小。则分割页块。如果合适则不进行操作,最后计算剩余空闲页个数并返回分配的页块地址。

  1. 修改函数 default_free_pages
static void
default_free_pages(struct Page *base, size_t n) {
    assert(n > 0);
    assert(PageReserved(base));

    list_entry_t *le = &free_list;
    struct Page * p;
    while((le=list_next(le)) != &free_list) {
      p = le2page(le, page_link);
      if(p>base){
        break;
      }
    }
    //list_add_before(le, base->page_link);
    for(p=base;p<base+n;p++){
      list_add_before(le, &(p->page_link));
    }
    base->flags = 0;
    set_page_ref(base, 0);
    ClearPageProperty(base);
    SetPageProperty(base);
    base->property = n;
    
    p = le2page(le,page_link) ;
    if( base+n == p ){
      base->property += p->property;
      p->property = 0;
    }
    le = list_prev(&(base->page_link));
    p = le2page(le, page_link);
    if(le!=&free_list && p==base-1){
      while(le!=&free_list){
        if(p->property){
          p->property += base->property;
          base->property = 0;
          break;
        }
        le = list_prev(le);
        p = le2page(le,page_link);
      }
    }

    nr_free += n;
    return ;
}

设计实现过程:这个函数的作用是释放已经使用完的页,把他们合并到freelist中。在freelist中查找合适的位置以供插入。改变被释放页的标志位,以及头部的计数器尝试在freelist中向高地址或低地址合并。

练习2:实现寻找虚拟地址对应的页表项(需要编程)

通过设置页表和对应的页表项,可建立虚拟内存地址和物理内存地址的对应关系。其中的get_pte函数是设置页表项环节中的一个重要步骤。此函数找到一个虚地址对应的二级页表项的内核虚地址,如果此二级页表项不存在,则分配一个包含此项的二级页表。本练习需要补全get_pte函数 in kern/mm/pmm.c,实现其功能。请仔细查看和理解get_pte函数中的注释。get_pte函数的调用关系图如下所示:
在这里插入图片描述

  1. 请描述页目录项(Page Directory Entry)和页表项(Page Table Entry)中每个组成部分的含义以及对ucore而言的潜在用处。

(1) 目录项(Page Directory Entry)

地址名称对ucore而言的潜在用处
31:12Page Table 4KB Aligned Address页表的起始物理地址,用于定位页表位置
11:9AvailPTE_AVAIL,保存给OS使用
8Ignored
7Page SizePTE_PS,用于确认页的大小
6PTE_MBZ
5AccessedPTE_A,用于确认对应页表是否被使用
4Cache DisabledPTE_PCD 用于cache
3Write ThroughPTE_PWT 用于cache
2User/SupervisorPTE_U,用于确认用户态下是否可以访问
1Read/WritePTE_W,用于确认页表是否可写,内存分配和释放时需要置位
0PresentPTE_P,用于确定对应的页表是否存在,如果为1表示存在,如果为0表示不存在,需要再分配一个物理页给页表

(2) 页表项(Page Table Entry)

地址名称对ucore而言的潜在用处
31:12Physical Page Address对应物理页的起始物理地址,用于定位物理也的位置
11:9AvailPTE_AVAIL,保存给OS使用
8Global
70PTE_MBZ
6DirtyPTE_D,脏位,用于确认数据是否有效
5AccessedPTE_A,用于确认对应页表是否被使用
4Cache DisabledPTE_PCD 用于cache
3Write ThroughPTE_PWT 用于cache
2User/SupervisorPTE_U,用于确认用户态下是否可以访问对应的物理页
1Read/WritePTE_W,用于确认对应的物理页是否可写
0PresentPTE_P,用于确认页表项所对应的物理页是否存在
  1. 如果ucore执行过程中访问内存,出现了页访问异常,请问硬件要做哪些事情?
①将引发页访问异常的地址将被保存在cr2寄存器中
②设置错误代码
③引发Page Fault,将外存的数据换到内存中
④进行上下文切换,退出中断,返回到中断前的状态
  1. 补全函数 get_pte
pte_t *
get_pte(pde_t *pgdir, uintptr_t la, bool create) {
    /* LAB2 EXERCISE 2: YOUR CODE
     *
     * If you need to visit a physical address, please use KADDR()
     * please read pmm.h for useful macros
     *
     * Maybe you want help comment, BELOW comments can help you finish the code
     *
     * Some Useful MACROs and DEFINEs, you can use them in below implementation.
     * MACROs or Functions:
     *   PDX(la) = the index of page directory entry of VIRTUAL ADDRESS la.
     *   KADDR(pa) : takes a physical address and returns the corresponding kernel virtual address.
     *   set_page_ref(page,1) : means the page be referenced by one time
     *   page2pa(page): get the physical address of memory which this (struct Page *) page  manages
     *   struct Page * alloc_page() : allocation a page
     *   memset(void *s, char c, size_t n) : sets the first n bytes of the memory area pointed by s
     *                                       to the specified value c.
     * DEFINEs:
     *   PTE_P           0x001                   // page table/directory entry flags bit : Present
     *   PTE_W           0x002                   // page table/directory entry flags bit : Writeable
     *   PTE_U           0x004                   // page table/directory entry flags bit : User can access
     */
#if 0
    pde_t *pdep = NULL;   // (1) find page directory entry
    if (0) {              // (2) check if entry is not present
                          // (3) check if creating is needed, then alloc page for page table
                          // CAUTION: this page is used for page table, not for common data page
                          // (4) set page reference
        uintptr_t pa = 0; // (5) get linear address of page
                          // (6) clear page content using memset
                          // (7) set page directory entry's permission
    }
    return NULL;          // (8) return page table entry
#endif
    pde_t *pdep = &pgdir[PDX(la)];
    if (!(*pdep & PTE_P)) {
        struct Page *page;
        if (!create || (page = alloc_page()) == NULL) {
            return NULL;
        }
        set_page_ref(page, 1);
        uintptr_t pa = page2pa(page);
        memset(KADDR(pa), 0, PGSIZE);
        *pdep = pa | PTE_U | PTE_W | PTE_P;
    }
    return &((pte_t *)KADDR(PDE_ADDR(*pdep)))[PTX(la)];
}

练习3:释放某虚地址所在的页并取消对应二级页表项的映射(需要编程)

当释放一个包含某虚地址的物理内存页时,需要让对应此物理内存页的管理数据结构Page做相关的清除处理,使得此物理内存页成为空闲;另外还需把表示虚地址与物理地址对应关系的二级页表项清除。请仔细查看和理解page_remove_pte函数中的注释。为此,需要补全在 kern/mm/pmm.c中的page_remove_pte函数。page_remove_pte函数的调用关系图如下所示:
在这里插入图片描述

  1. 数据结构Page的全局变量(其实是一个数组)的每一项与页表中的页目录项和页表项有无对应关系?如果有,其对应关系是啥?

当页目录项或页表项有效时,二者之间有对应关系。练习2的问题其实已经说明了一些情况,实际上,pages每一项记录一个物理页的信息,而每个页目录项记录一个页表的信息,每个页表项则记录一个物理页的信息。可以说,页目录项保存的物理页面地址(即某个页表)以及页表项保存的物理页面地址都对应于Page数组中的某一页。

  1. 补全函数 page_remove_pte
//page_remove_pte - free an Page sturct which is related linear address la
//                - and clean(invalidate) pte which is related linear address la
//note: PT is changed, so the TLB need to be invalidate 
static inline void
page_remove_pte(pde_t *pgdir, uintptr_t la, pte_t *ptep) {
    /* LAB2 EXERCISE 3: YOUR CODE
     *
     * Please check if ptep is valid, and tlb must be manually updated if mapping is updated
     *
     * Maybe you want help comment, BELOW comments can help you finish the code
     *
     * Some Useful MACROs and DEFINEs, you can use them in below implementation.
     * MACROs or Functions:
     *   struct Page *page pte2page(*ptep): get the according page from the value of a ptep
     *   free_page : free a page
     *   page_ref_dec(page) : decrease page->ref. NOTICE: ff page->ref == 0 , then this page should be free.
     *   tlb_invalidate(pde_t *pgdir, uintptr_t la) : Invalidate a TLB entry, but only if the page tables being
     *                        edited are the ones currently in use by the processor.
     * DEFINEs:
     *   PTE_P           0x001                   // page table/directory entry flags bit : Present
     */
#if 0
    if (0) {                      //(1) check if page directory is present
        struct Page *page = NULL; //(2) find corresponding page to pte
                                  //(3) decrease page reference
                                  //(4) and free this page when page reference reachs 0
                                  //(5) clear second page table entry
                                  //(6) flush tlb
    }
#endif
    if (*ptep & PTE_P) {
        struct Page *page = pte2page(*ptep);
        if (page_ref_dec(page) == 0) {
            free_page(page);
        }
        *ptep = 0;
        tlb_invalidate(pgdir, la);
    }
}

//page_remove - free an Page which is related linear address la and has an validated pte
void
page_remove(pde_t *pgdir, uintptr_t la) {
    pte_t *ptep = get_pte(pgdir, la, 0);
    if (ptep != NULL) {
        page_remove_pte(pgdir, la, ptep);
    }
}

(参考资料1:https://blog.csdn.net/tangyuanzong/article/details/78913388)
(参考资料2:https://blog.csdn.net/dingdingdodo/article/details/100622753)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值