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;
}
评论
ValineWaline