static u_int asid_bitmap[2] = {0}; // 位图法管理64个asid static u_int asid_alloc(){ int i, index, inner; for (i = 0; i < 64; ++i) { index = i >> 5; // index标记索引,即具体是哪个asid_bitmap inner = i & 31; // i&31,即获取低5位,舍弃第6位 if ((asid_bitmap[index] & (1 << inner)) == 0) { // 将管理i对应的位取出,判断是否为0,若为0则说明该asid可以申请。 asid_bitmap[index] |= 1 << inner; // 将对应的位置1,标记这个asid已经被申请 return i; } } panic("too many processes!"); // 若最后也没有找到可以用的asid,返回报错信息 }
envid2env
envid2env(u_int envid, struct Env **penv, int checkperm)
根据envid找到对应的env
env_alloc
返回值:int
env_setup_vm
env_setup_vm(struct Env *e)
env_create
返回值:void
创建进程。以默认优先级申请一个env,实际上是调用env_create_priority。
1 2 3 4 5 6
void env_create(u_char *binary, intsize) { /* Step 1: Use env_create_priority to alloc a new env with priority 1 */ env_create_priority(binary, size, 1); }
env_create_priority
返回值:void
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
void env_create_priority(u_char *binary, intsize, int priority) { structEnv *e; /* Step 1: Use env_alloc to alloc a new env. */ if (env_alloc(&e, 0) != 0) { return; } /* Step 2: assign priority to the new env. */ e->env_pri = priority; /* Step 3: Use load_icode() to load the named elf binary, and insert it into env_sched_list using LIST_INSERT_HEAD. */ load_icode(e, binary, size); LIST_INSERT_HEAD(&env_sched_list[0], e, env_sched_link); }
staticvoid load_icode(struct Env *e, u_char *binary, u_int size) { /* Hint: * You must figure out which permissions you'll need * for the different mappings you create. * Remember that the binary image is an a.out format image, * which contains both text and data. */ structPage *p = NULL; u_long entry_point; u_long r; u_long perm;
/* Step 1: alloc a page. */ perm = PTE_R; if ((r = page_alloc(&p)) != 0) { return; } /* Step 2: Use appropriate perm to set initial stack for new Env. */ /* Hint: Should the user-stack be writable? */ if ((r = page_insert(e->env_pgdir, p, USTACKTOP - BY2PG, perm)) != 0) { return; } if ((r = load_elf(binary, size, &entry_point, e, load_icode_mapper)) != 0) { return; }
/* Step 3: load the binary using elf loader. */
/* Step 4: Set CPU's PC register as appropriate value. */ e->env_tf.pc = entry_point; }
load_icode_mapper
返回值:int
特殊类型:static
static int load_icode_mapper(u_long va, u_int32_t sgsize,u_char *bin, u_int32_t bin_size, void *user_data)
intload_elf(u_char *binary, intsize, u_long *entry_point, void *user_data, int (*map)(u_long va, u_int32_t sgsize, u_char *bin, u_int32_t bin_size, void *user_data)) { Elf32_Ehdr *ehdr = (Elf32_Ehdr *)binary; Elf32_Phdr *phdr = NULL; /* As a loader, we just care about segment, * so we just parse program headers. */ u_char *ptr_ph_table = NULL; Elf32_Half ph_entry_count; Elf32_Half ph_entry_size; int r; // check whether `binary` is a ELF file. if (size < 4 || !is_elf_format(binary)) { return-1; }
while (ph_entry_count--) { phdr = (Elf32_Phdr *)ptr_ph_table;
if (phdr->p_type == PT_LOAD) { /* Your task here! */ /* Real map all section at correct virtual address.Return < 0 if error. */ /* Hint: Call the callback function you have achieved before. */ r = map(phdr->p_vaddr, phdr->p_memsz, binary + phdr->p_offset, phdr->p_filesz, user_data); if (r != 0) { return r; } }
ptr_ph_table += ph_entry_size; }
*entry_point = ehdr->e_entry; return0; }
kclock_init
位置:lib/kclock.c
初始化时钟,主要调用set_timer
SAVE_ALL
位置:include/stackframe.h
lcontext
汇编函数,更换地址空间,在进程切换时用到
1 2 3 4 5 6
LEAF(lcontext) .extern mCONTEXT sw a0,mCONTEXT jr ra nop END(lcontext)
env_pop_tf
位置:lib/env_asm.S
1
externvoidenv_pop_tf(struct Trapframe *tf, int id);
void env_run(struct Env *e) { /* Step 1: save register state of curenv. */ /* Hint: if there is an environment running, * you should switch the context and save the registers. * You can imitate env_destroy() 's behaviors.*/ if (curenv) { structTrapframe *old = (structTrapframe *)(TIMESTACK - sizeof(structTrapframe)); bcopy(old, &(curenv->env_tf), sizeof(struct Trapframe)); curenv->env_tf.pc = curenv->env_tf.cp0_epc; }
/* Step 2: Set 'curenv' to the new environment. */ curenv = e;
/* Step 3: Use lcontext() to switch to its address space. */ lcontext(curenv->env_pgdir);
/* Step 4: Use env_pop_tf() to restore the environment's * environment registers and return to user mode. * * Hint: You should use GET_ENV_ASID there. Think why? * (read <see mips run linux>, page 135-144) */ env_pop_tf(&(curenv->env_tf), GET_ENV_ASID(curenv->env_id)); }
NESTED(handle_sys,TF_SIZE, sp) SAVE_ALL // Macro used to save trapframe CLI // Clean Interrupt Mask nop .set at // Resume use of $at
// TODO: Fetch EPC from Trapframe, calculate a proper value and store it back to trapframe. lw t0, TF_EPC(sp) addiu t0, t0, 4 sw t0, TF_EPC(sp) // TODO: Copy the syscall number into $a0. lw a0, TF_REG4(sp)
addiu a0, a0, -__SYSCALL_BASE // a0 <- relative syscall number sll t0, a0, 2 // t0 <- relative syscall number times 4 la t1, sys_call_table // t1 <- syscall table base addu t1, t1, t0 // t1 <- table entry of specific syscall lw t2, 0(t1) // t2 <- function entry of specific syscall
lw t0, TF_REG29(sp) // t0 <- user stack pointer lw t3, 16(t0) // t3 <- the 5th argument of msyscall lw t4, 20(t0) // t4 <- the 6th argument of msyscall
// TODO: Allocate a space of six arguments on current kernel stack and copy the six arguments to proper location lw a0, TF_REG4(sp) lw a1, TF_REG5(sp) lw a2, TF_REG6(sp) lw a3, TF_REG7(sp) addiu sp, sp, -24 sw a0, 0(sp) sw a1, 4(sp) sw a2, 8(sp) sw a3, 12(sp) sw t3, 16(sp) sw t4, 20(sp) jalr t2 // Invoke sys_* function nop // TODO: Resume current kernel stack addiu sp, sp, 24
sw v0, TF_REG2(sp) // Store return value of function sys_* (in $v0) into trapframe
j ret_from_exception // Return from exeception nop END(handle_sys)
kclock_init
位置:lib/kclock.c
kernel clock init,时钟初始化
1 2 3 4
voidkclock_init(void) { set_timer(); }
set_timer
位置:kclock_asm.S
设置时钟
1 2 3 4 5 6 7 8 9 10
LEAF(set_timer)
li t0, 0xc8 sb t0, 0xb5000100 sw sp, KERNEL_SP setup_c0_status STATUS_CU0|0x1001 0 jr ra
This is copyright.