ucore lab 8

练习0:填写已有实验

请把你做的实验代码填入本实验中代码中有“LAB1”/“LAB2”/“LAB3”/“LAB4”/“LAB5”/“LAB6” /“LAB7”的注释相应部分。并确保编译通过。注意:为了能够正确执行lab8的测试应用程序,可能需对已完成的实验1/2/3/4/5/6/7的代码进行进一步改进。

vmm.c default_pmm.c pmm.c proc.c swap_fifo.c trap.c check_sync.c
proc.c: 
static struct proc_struct *alloc_proc(void) {
   
    //初始化PCB下的fs
    proc->filesp = NULL;
}
int do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) {
   
    //使用copy_fs复制父进程的fs到子进程中
    if (copy_fs(clone_flags, proc) != 0) {
   
        goto bad_fork_cleanup_kstack;
    }
}

练习1: 完成读文件操作的实现(需要编码)

​ 首先了解打开文件的处理流程,然后参考本实验后续的文件读写操作的过程分析,编写在sfs_inode.c中sfs_io_nolock读文件中数据的实现代码。

static int sfs_io_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, void *buf, off_t offset, size_t *alenp, bool write) {
   
    // 先判断第一块的情况 如果没对齐 就从偏移的地方读取
    if ((blkoff = offset % SFS_BLKSIZE) != 0)  {
   
        // 判断 endpos 和 offset 是否在同一块中
        // 若为同一块 则 size 为 endpos - offset
        // 若不为同一块 则 size 为 SFS_BLKSIZE - blkoff(偏移) 为 第一块要读的大小
        size = (nblks != 0) ? (SFS_BLKSIZE - blkoff) : (endpos - offset);
        if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) {
   
            goto out;
        }
        if ((ret = sfs_buf_op(sfs, buf, size, ino, blkoff)) != 0) {
   
            goto out;
        }
        alen += size;
        if (nblks == 0) {
   
            goto out;
        }
        buf += size, blkno++; nblks--;
    }

    // 中间对齐的情况
    size = SFS_BLKSIZE;
    while (nblks != 0) {
   
        if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) {
   
            goto out;
        }
        if ((ret = sfs_block_op(sfs, buf, ino, 1)) != 0) {
   
            goto out;
        }
        alen += size, buf += size, blkno++, nblks--;
    }

    // 末尾最后一块没对齐的情况
    if ((size = endpos % SFS_BLKSIZE) != 0) {
   
        if ((ret = sfs_bmap_load_nolock(sfs, sin, blkno, &ino)) != 0) {
   
            goto out;
        }
        if ((ret = sfs_buf_op(sfs, buf, size, ino, 0)) != 0) {
   
            goto out;
        }
        alen += size;
    }
}

练习2: 完成基于文件系统的执行程序机制的实现(需要编码)

​ 改写proc.c中的load_icode函数和其他相关函数,实现基于文件系统的执行程序机制。执行:make qemu。如果能看看到sh用户程序的执行界面,则基本成功了。如果在sh用户界面上可以执行”ls”,”hello”等其他放置在sfs文件系统中的其他执行程序,则可以认为本实验基本成功。

在 Lab 7 的基础上进行修改 读elf文件变成了从磁盘上读 而不是直接在内存中读

参数在栈中的布局:

| High Address |
----------------
|   Argument   |
|      n       |
----------------
|     ...      |
----------------
|   Argument   |
|      1       |
----------------
|    padding   |
----------------
|   null ptr   |
----------------
|  Ptr Arg n   |
----------------
|     ...      |
----------------
|  Ptr  Arg 1  |
----------------
|  Arg  Count  | <-- user esp
----------------
| Low  Address |

实现:

static int load_icode(int fd, int argc, char **kargv) {
    //setup argc, argv 
    //先算出所有参数加起来的长度
    uint32_t argv_size=0, i;
    for (i = 0; i < argc; i ++) {
        argv_size += strnlen(kargv[i],EXEC_MAX_ARG_LEN ) + 1;
    }
    //用户栈顶减去所有参数加起来的长度,再4字节对齐,找到真正存放字符串参数的栈的位置
    char *arg_str = (USTACKTOP - argv_size) & 0xfffffffc;
    //放字符串参数的栈的位置的下面,是存放指向字符串参数的指针
    int32_t *arg_ptr = (int32_t *)arg_str - argc;
    //指向字符串参数的指针下面是参数的个数
    int32_t *stacktop = arg_ptr - 1;
    *stacktop = argc;
    for (i = 0; i < argc; i ++){
        uint32_t arg_len = strnlen(kargv[i], EXEC_MAX_ARG_LEN);
        strncpy(arg_str, kargv[i], argv_size);
        *arg_ptr = arg_str;
        arg_str += arg_len + 1;
        ++arg_ptr;
    }
}

参考:

​ [文章](