LAB1

kern/debug/kdebug.c

print_stackframe

void
print_stackframe(void) {
    // read_ebp() && read_eip 直接看函数调用就行
    uint32_t ebp = read_ebp();
    uint32_t eip = read_eip();

    // loop
    int i,j;
    for(i = 0;i < STACKFRAME_DEPTH && ebp != 0;i++){
        // format 仿照 print_kerninfo() 写的
        cprintf("ebp:0x%08x",ebp);
        cprintf("eip:0x%08x",eip);
        cprintf("args:");
        // entry args
        uint32_t *args= (uint32_t*)ebp +2;
        // inner loop
        for(j = 0 ; j < 4;j++){
            cprintf("0x%08x",args[j]);
        }
        cprintf("\n");
        print_debuginfo(eip-1);
        // pop 更新数据
        eip = ((uint32_t *)ebp)[1];
        ebp = ((uint32_t *)ebp)[0];
    }

kern/trap/trap.c

idt_init

void
idt_init(void) {
    extern uintptr_t __vectors[];
    int i;
    for(i=0; i<sizeof(idt)/sizeof(struct gatedesc); i++){
        SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL);
    }
    SETGATE(idt[T_SWITCH_TOK], 0, GD_KTEXT, __vectors[T_SWITCH_TOK], DPL_USER);
    lidt(&idt_pd);
}

trap_dispatch

//trap_dispatch -> switch -> case IRQ_OFFSET + IRQ_TIMER:
case IRQ_OFFSET + IRQ_TIMER:
        ticks++;
        if(ticks%TICK_NUM==0)
            print_ticks();
        break;

LAB2

kern/mm/default_pmm.c

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 = p->property = 0;
        set_page_ref(p, 0);
    }
    base->property = n;
    SetPageProperty(base);
    nr_free += n;
    list_add_before(&free_list, &(base->page_link));
}

default_alloc_pages

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;
            SetPageProperty(p);
            list_add_after(&(page->page_link), &(p->page_link));
        }
        list_del(&(page->page_link));
        nr_free -= n;
        ClearPageProperty(page);
    }
    return page;
}

default_free_pages

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;
        set_page_ref(p, 0);
    }
    base->property = n;
    SetPageProperty(base);
    list_entry_t *le = list_next(&free_list);
    while (le != &free_list) {
        p = le2page(le, page_link);
        le = list_next(le);
        if (base + base->property == p) {
            base->property += p->property;
            ClearPageProperty(p);
            list_del(&(p->page_link));
        }
        else if (p + p->property == base) {
            p->property += base->property;
            ClearPageProperty(base);
            base = p;
            list_del(&(p->page_link));
        }
    }
    nr_free += n;
    for(le = list_next(&free_list); le != &free_list; le = list_next(le))
    {
        p = le2page(le, page_link);
        if (base + base->property <= p) {
            assert(base + base->property != p);
            break;
        }
    }
    list_add_before(le, &(base->page_link));
}

kern/mm/pmm.c

get_pte

pte_t *
get_pte(pde_t *pgdir, uintptr_t la, bool create) {
    // 获取传入的线性地址中所对应的页目录条目的物理地址
    pde_t *pdep = &pgdir[PDX(la)];
    // 如果该条目不可用(not present)
    if (!(*pdep & PTE_P)) {
        struct Page *page;
        // 如果分配页面失败,或者不允许分配,则返回NULL
        if (!create || (page = alloc_page()) == NULL)
            return NULL;
        // 设置该物理页面的引用次数为1
        set_page_ref(page, 1);
        // 获取当前物理页面所管理的物理地址
        uintptr_t pa = page2pa(page);
        // 清空该物理页面的数据。需要注意的是使用虚拟地址
        memset(KADDR(pa), 0, PGSIZE);
        // 将新分配的页面设置为当前缺失的页目录条目中
        // 之后该页面就是其中的一个二级页面
        *pdep = pa | PTE_U | PTE_W | PTE_P;
    }
    // 返回在pgdir中对应于la的二级页表项
    return &((pte_t *)KADDR(PDE_ADDR(*pdep)))[PTX(la)];
}

page_remove_pte

static inline void
page_remove_pte(pde_t *pgdir, uintptr_t la, pte_t *ptep) {
    // 如果传入的页表条目是可用的
    if (*ptep & PTE_P) {
        // 获取该页表条目所对应的地址
        struct Page *page = pte2page(*ptep);
        // 如果该页的引用次数在减1后为0
        if (page_ref_dec(page) == 0)
            // 释放当前页
            free_page(page);
        // 清空PTE
        *ptep = 0;
        // 刷新TLB内的数据
        tlb_invalidate(pgdir, la);
    }
}

下面的改动应该是LAB2独有的

tools/kernel.ld

. = 0x00100000;

kern/mm/memlayout.h

#define KERNBASE            0x00000000

kern/init/entry.S

# movl %eax, %cr0

LAB3

kern/mm/vmm.c

do_pgfault

ptep = get_pte(mm->pgdir, addr, 1); // 获取当前发生缺页的虚拟页对应的PTE
if (*ptep == 0) { // 如果需要的物理页是没有分配而不是被换出到外存中
    struct Page* page = pgdir_alloc_page(mm->pgdir, addr, perm); // 分配物理页,并且与对应的虚拟页建立映射关系
} else {
    if (swap_init_ok) { // 判断是否当前交换机制正确被初始化
        struct Page *page = NULL;
        swap_in(mm, addr, &page); // 将物理页换入到内存中
        page_insert(mm->pgdir, page, addr, perm); // 将物理页与虚拟页建立映射关系
        swap_map_swappable(mm, addr, page, 1); // 设置当前的物理页为可交换的
        page->pra_vaddr = addr;
    } else {
        cprintf("no swap_init_ok but ptep is %x, failed\n",*ptep);
        goto failed;
    }// 将物理页从外存换到内存中,练习2中需要实现的内容

kern/mm/swap_fifo.c

map_swappable

static int
_fifo_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in)
{
    list_entry_t *head=(list_entry_t*) mm->sm_priv;
    list_entry_t *entry=&(page->pra_page_link);
 
    assert(entry != NULL && head != NULL);
    list_add(head, entry);
    return 0;
}

swap_out_victim

static int
_fifo_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page, int in_tick)
{
     list_entry_t *head=(list_entry_t*) mm->sm_priv;
         assert(head != NULL);
     assert(in_tick==0);
     list_entry_t *entry = head -> prev;
     struct Page *page = le2page(entry,pra_page_link);
     list_del(entry);
     *ptr_page = page;
     return 0;return 0;
}

LAB4

kern/process/proc.c

alloc_proc

static struct proc_struct *
alloc_proc(void) {
  struct proc_struct *proc = kmalloc(sizeof(struct proc_struct));
  if (proc != NULL) {
    proc->state = PROC_UNINIT;
    proc->pid = -1;
    proc->runs = 0;
    proc->kstack = 0;
    proc->need_resched = 0;
    proc->parent = NULL;
    proc->mm = NULL;
    memset(&(proc->context), 0, sizeof(struct context));
    proc->tf = NULL;
    proc->cr3 = boot_cr3;
    proc->flags = 0;
    memset(proc->name, 0, PROC_NAME_LEN);
  }
  return proc;
}

do_fork

int
do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) {
    int ret = -E_NO_FREE_PROC;
    struct proc_struct *proc;
    if (nr_process >= MAX_PROCESS) {
        goto fork_out;
    }
    ret = -E_NO_MEM;
    // 调用alloc_proc,首先获得一块用户信息块。
    if ((proc = alloc_proc()) == NULL)
      goto fork_out;
    proc->parent = current;
    // 为进程分配一个内核栈
    if (setup_kstack(proc) != 0)
      goto bad_fork_cleanup_proc;
    // 复制原进程的内存管理信息到新进程
    if (copy_mm(clone_flags, proc) != 0)
      goto bad_fork_cleanup_kstack;
    // 复制原进程上下文到新进程
    copy_thread(proc, stack, tf);
    // 将新进程添加到进程列表
    proc->pid = get_pid();
    hash_proc(proc);
    list_add(&proc_list, &(proc->list_link));
    nr_process ++;
    // 唤醒新进程
    wakeup_proc(proc);
    // 返回新进程号
    ret = proc->pid;
fork_out:
    return ret;

bad_fork_cleanup_kstack:
    put_kstack(proc);
bad_fork_cleanup_proc:
    kfree(proc);
    goto fork_out;
}