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;
}
}
参考:
[文章](