ucore lab2练习1

实现 first-fit 连续物理内存分配算法

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

完成这个练习之前,应该首先学习一下ucore 内存管理流程,这个在实验指导书上有说明。

分析一下pmm_init函数:

void
pmm_init(void) {
    // We've already enabled paging
    boot_cr3 = PADDR(boot_pgdir);

    //这个函数初始化pmm_manager,把里面的函数指针指向default_pmm.c里面的几个函数
    init_pmm_manager();

    //查找空闲内存,为其创建空闲分页列表
    page_init();

    //use pmm->check to verify the correctness of the alloc/free function in a pmm
    check_alloc_page();

    check_pgdir();

    static_assert(KERNBASE % PTSIZE == 0 && KERNTOP % PTSIZE == 0);

    // recursively insert boot_pgdir in itself
    // to form a virtual page table at virtual address VPT
    boot_pgdir[PDX(VPT)] = PADDR(boot_pgdir) | PTE_P | PTE_W;

    // map all physical memory to linear memory with base linear addr KERNBASE
    // linear_addr KERNBASE ~ KERNBASE + KMEMSIZE = phy_addr 0 ~ KMEMSIZE
    boot_map_segment(boot_pgdir, KERNBASE, KMEMSIZE, 0, PTE_W);

    // Since we are using bootloader's GDT,
    // we should reload gdt (second time, the last time) to get user segments and the TSS
    // map virtual_addr 0 ~ 4G = linear_addr 0 ~ 4G
    // then set kernel stack (ss:esp) in TSS, setup TSS in gdt, load TSS
    gdt_init();

    //now the basic virtual memory map(see memalyout.h) is established.
    //check the correctness of the basic virtual memory map.
    check_boot_pgdir();

    print_pgdir();

}

// you should rewrite functions: `default_init`, `default_init_memmap`,
// `default_alloc_pages`, `default_free_pages`.


//  manage the free memory blocks using a list. The struct `free_area_t` is used
// for the management of free memory blocks.
//   * `list` is a simple doubly linked list implementation. You should know how to
//  * USE `list_init`, `list_add`(`list_add_after`), `list_add_before`, `list_del`,
//  * `list_next`, `list_prev`.

//  *  There's a tricky method that is to transform a general `list` struct to a
//  * special struct (such as struct `page`), using the following MACROs: `le2page`
//  * (in memlayout.h), (and in future labs: `le2vma` (in vmm.h), `le2proc` (in
//  * proc.h), etc).

从上面的大概描写我们知道,要实现这个方法就要重写这几个函数,然后要了解一下双向链表“list”。先看一下这里面的代码:

struct list_entry {
    struct list_entry *prev, *next;
};

typedef struct list_entry list_entry_t;                     //双向循环链表

//__attribute__((always_inline))的意思是把这个函数进行强制内联。

//初始化一个节点
static inline void list_init(list_entry_t *elm) __attribute__((always_inline));

//把elm插入到listelm中,插入到第一个节点
static inline void list_add(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));


//把elm插入到listelm中,插入到第一个节点
static inline void list_add_before(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));


//把elm插入到listelm中,插入到尾节点
static inline void list_add_after(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));

//删除这个节点
static inline void list_del(list_entry_t *listelm) __attribute__((always_inline));

//删除这个节点后并初始化这个节点(改变头尾指针)
static inline void list_del_init(list_entry_t *listelm) __attribute__((always_inline));

//判断是否为空
static inline bool list_empty(list_entry_t *list) __attribute__((always_inline));

//返回这个节点的父节点
static inline list_entry_t *list_next(list_entry_t *listelm) __attribute__((always_inline));

//返回这个节点的子节点
static inline list_entry_t *list_prev(list_entry_t *listelm) __attribute__((always_inline));

以上便是list的基本用法了。

接下来需要分析一下内存初始化的步骤,先进入kern_init,找到这个函数:

    pmm_init(); 

然后这个函数里面有重要的两步:

init_pmm_manager();
page_init();

其中第一个函数是初始化全局内存管理器pmm_manager,是其函数指针指向default_pmm.c里面的几个函数。
然后进入page_init函数,这个函数根据内存里面的空闲区域(空闲区域是在entry里面找的,找完后放到0x8000处)。根据空闲的内存块进行分页处理。(处理的过程中会调用default_init_memmap函数)。

根据以上内容先修改一下default_init_memmap函数:

static void
default_init_memmap(struct Page *base, size_t n) {     //空闲块第一个页选项地址,n表示有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;
    list_add(&free_list, &(base->page_link));
}

其实上面这段代码已经实现了很多功能,只有最后一步list_add改成list_add_before就好了,因为添加的时候,地址要维持递增。

default_alloc_pages函数没什么要改的。

default_free_pages函数,最后面加个过程就好了,同样是为了维持地址递增。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值