北航操作系统实验2019:Lab4-1代码实现参考

北航操作系统实验2019:Lab4-1代码实现参考

部分实现参考自Github前辈们的项目,经过一定程度的勘误。

如果这份代码中存在任何问题或错误,请务必不吝在评论区指出。

Exercise 4.1

// user/syscall_wrap.S
LEAF(msyscall)
    // TODO: 执行syscall指令,然后从函数返回
    syscall
    jr ra
    nop
END(msyscall)

Exercise 4.2

// lib/syscall.S
NESTED(handle_sys,TF_SIZE, sp)
    SAVE_ALL                            // 用于保存现场的宏
    CLI                                 // 关闭全局中断
    nop
    .set at                             // 恢复$at寄存器的使用

    // TODO: 取出EPC的值,计算一个合理的值(+4)后存回去
    lw t1, TF_EPC(sp)
    addiu t1, t1, 4
    sw t1, TF_EPC(sp)

    // TODO: 将系统调用号的值存入a0。
    // 此处因为本身系统调用号就在a0中,所以什么都不做。

    addiu   a0, a0, -__SYSCALL_BASE     // a0 <- 相对系统调用号
    sll     t0, a0, 2                   // t0 <- 相对系统调用号乘4
    la      t1, sys_call_table          // t1 <- 系统调用表的基地址
    addu    t1, t1, t0                  // t1 <- 特定系统调用的入口
    lw      t2, 0(t1)                   // t2 <- 读取特定系统调用的函数入口

    lw      t0, TF_REG29(sp)            // t0 <- 用户栈顶
    lw      t3, 16(t0)                  // t3 <- syscall的第5个参数
    lw      t4, 20(t0)                  // t4 <- syscall的第6个参数

    // TODO: 在当前栈内分配6个参数的空间,并将6个参数复制到合理的位置。
    // 六个参数的位置分别是:前4个参数在a0~a3,第5、6个参数在栈内偏移16、20的位置。
    //lw a0, TF_REG4(sp) ----- 我本地测试,这行加上之后,第二部分会7/8,不加则8/8
    addiu sp, sp, -24
    sw t3, 16(sp)
    sw t4, 20(sp)

    jalr    t2                          // 调用sys_*函数
    nop

    // TODO: 恢复当前的内核栈指针
    addiu sp, sp, 24

    sw      v0, TF_REG2(sp)             // 将sys_*函数的返回值存入待恢复现场的v0寄存器

    j       ret_from_exception          // 从异常状态中返回
    nop
END(handle_sys)

Exercise 4.3~4.6

// lib/syscall_all.c
void sys_yield(void)
{
        struct Trapframe *src = (struct Trapframe *)(KERNEL_SP - sizeof(struct Trapframe));
        struct Trapframe *dst = (struct Trapframe *)(TIMESTACK - sizeof(struct Trapframe));

        bcopy((void*)src, (void*)dst, sizeof(struct Trapframe));
        sched_yield();
}

int sys_mem_alloc(int sysno, u_int envid, u_int va, u_int perm)
{
        struct Env *env;
        struct Page *ppage;
        int ret;
        ret = 0;

        if (va >= UTOP || va < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_alloc - va illegal\n");
                return -E_UNSPECIFIED;
        }

        if ((perm & PTE_COW) || !(perm & PTE_V)) {
                printf("Error in lib/syscall_all.c, sys_mem_alloc - perm illegal\n");
                return -E_INVAL;
        }

        if (envid2env(envid, &env, 0) < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_alloc - envid illegal\n");
                return -E_BAD_ENV;
        }

        if (page_alloc(&ppage) < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_alloc - memory insufficient\n");
                return -E_NO_MEM;
        }

        if (page_insert(env->env_pgdir, ppage, va, perm) < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_alloc - pgdir insert failed\n");
                return -E_NO_MEM;
        }

        return 0;
}


int sys_mem_map(int sysno, u_int srcid, u_int srcva, u_int dstid, u_int dstva, u_int perm)
{
        int ret;
        u_int round_srcva, round_dstva;
        struct Env *srcenv;
        struct Env *dstenv;
        struct Page *ppage;
        Pte *ppte;

        ppage = NULL;
        ret = 0;
        round_srcva = ROUNDDOWN(srcva, BY2PG);
        round_dstva = ROUNDDOWN(dstva, BY2PG);

        if (srcva >= UTOP || dstva >= UTOP || srcva < 0 || dstva < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_map - va illegal\n");
                return -E_UNSPECIFIED;
        }

        if (!(perm & PTE_V)) {
                printf("Error in lib/syscall_all.c, sys_mem_map - perm illegal\n");
                return -E_INVAL;
        }

        if (envid2env(srcid, &srcenv, 0) < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_map - srcid illegal\n");
                return -E_BAD_ENV;
        }


        if (envid2env(dstid, &dstenv, 0) < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_map - dstid illegal\n");
                return -E_BAD_ENV;
        }

        if ((ppage = page_lookup(srcenv -> env_pgdir, round_srcva, &ppte)) == 0) {
                printf("Error in lib/syscall_all.c, sys_mem_map - pgdir insert failed\n");
                return -E_UNSPECIFIED;
        }

        if (page_insert(dstenv -> env_pgdir, ppage, round_dstva, perm) < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_map - dstid illegal\n");
                return -E_NO_MEM;
        }

        return ret;
}

int sys_mem_unmap(int sysno, u_int envid, u_int va)
{
        int ret = 0;
        struct Env *env;

        if (va >= UTOP || va < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_unmap - va illegal\n");
                return -E_INVAL;
        }

        if (envid2env(envid, &env, PTE_V) < 0) {
                printf("Error in lib/syscall_all.c, sys_mem_unmap - envid illegal\n");
                return -E_INVAL;
        }

        page_remove(env -> env_pgdir, va);

        return ret;
}

Exercise 4.7

// lib/syscall_all.c
void sys_ipc_recv(int sysno, u_int dstva)
{
        if (dstva >= UTOP) {
                return;
        }
        curenv -> env_ipc_recving = 1;
        curenv -> env_ipc_dstva = dstva;
        curenv -> env_status = ENV_NOT_RUNNABLE;
        LIST_REMOVE(curenv, env_sched_link);  // Lab4可有可无
        sys_yield();
}

int sys_ipc_can_send(int sysno, u_int envid, u_int value, u_int srcva, u_int perm)
{

        int r;
        struct Env *e;
        struct Page *p;
        Pte *ppte;

        if (srcva >= UTOP || srcva < 0) {
                return -E_INVAL;
        }

        if (envid2env(envid, &e, 0) < 0) {
                return -E_INVAL;
        }

        if (e -> env_ipc_recving == 0) {
                return -E_IPC_NOT_RECV;
        }

        if (srcva != 0) {
                e -> env_ipc_perm = perm|PTE_V|PTE_R;
        }
        e -> env_ipc_recving = 0;
        e -> env_status = ENV_RUNNABLE;
        LIST_INSERT_HEAD(&env_sched_list[0], e, env_sched_link);  // Lab4可有可无
        e -> env_ipc_value = value;
        e -> env_ipc_from = curenv -> env_id;

        return 0;
}

一并需要修改的地方

// Lab3: lib/sched.c
void sched_yield(void)
{
        static struct Env *cur = NULL;
        static u_int curtime = 0;
        static int x = 0;
        while (curtime <= 0 || cur && cur -> env_status != ENV_RUNNABLE) {
                if (cur != NULL) {
                        LIST_REMOVE(cur, env_sched_link);
                        LIST_INSERT_HEAD(&env_sched_list[1-x], cur, env_sched_link);
                }
                while ((LIST_FIRST(&env_sched_list[x])) == NULL) {
                        x = 1 - x;
                }
                cur = LIST_FIRST(&env_sched_list[x]);
                curtime = cur -> env_pri;
        }
        curtime--;
        env_run(cur);
}
上一篇:Dos命令 - 获取系统信息并存放到D盘下


下一篇:Windows系统怎么查看电脑的系统位数?