ChCore Lab3 Report
SJTU ChCore Lab3 思考题个人解答
ChCore Lab3 Report
实验记录
init_thread_ctx
线程上下文的初始化需要记录以下内容:
SP_EL0: 指向用户栈顶ELR_EL1: 指向用户程序入口地址SPSR_EL1: 设置为0,表示从 EL1 切换到 EL0 时,使用EL0t模式- 设置为线程状态为
INIT - 设置线程类型 (
USER/SHADOW/REGISTER/TRACEE, 详见kernel/include/sched/sched.h) - 设置线程亲和性,budget,priority 等调度相关信息
- 设置线程内核栈状态,退出状态
思考题
思考内核从完成必要的初始化到第一次切换到用户态程序的过程是怎么样的?尝试描述一下调用关系。
调用关系大致如下:
graph LR
subgraph main
direction LR
init[init...] --> callNode["create_root_thread()"] --> sched["sched()"] --> eret["eret(switch_contect())"]
end
可以看到,初始化后内核主要做了三件事:
- 创建第一个根线程
- 调用调度器
- 用 EL1 切换回用户态
我们主要关注创建根线程的过程:
graph LR
subgraph create_root_thread
direction TB
load_elf_meta --> init_root_cap_group --> init_stack --> alloc_thread_obj --> init_elf_segs --> alloc_prepare_env --> init_thread --> init_cap --> flush_cache --> enqueue_thread
end
该函数主要做了几件事:
- 读取 ELF 文件元信息
- 创建并初始化根能力组,并根据 cap 获取 vmspace 内核对象,后续 VMR 和 PMO 的映射都是基于该 vmspace 进行的
- 创建用户栈对应的 PMO 和 VMR
- 创建线程内核对象
- 根据元信息初始化 ELF 的各个段,并创建对应的 PMO 和 VMR 及映射
- 完成 vmspace 的初始化后,放回到对应 slot 中
- 创建并初始化用户态运行环境
- 初始化线程,并将线程内核对象放到根能力组的 slot 中
- flush cache 并将线程放入调度器的就绪队列
尝试描述
printf如何调用到chcore_stdout_write函数。
大致的调用关系如下:
graph LR
subgraph user
direction LR
printf["printf()"] --> vfprintf["vfprintf()"] --> fwrite["f->write()"] --> syscall["syscall(SYS_putstr)"]
end
subgraph kernel
direction LR
putstr["sys_putstr()"] --> uart["uart_send()"]
end
syscall -->|trap| putstr
在 ChCore 中,输出流是以文件描述符的形式存在,因此 f->write 实际上调用的是 stdout 的对应的 write 函数:
1
2
3
4
5
6
7
8
struct fd_ops stdout_ops = {
.read = chcore_stdio_read,
.write = chcore_stdout_write,
.close = chcore_stdout_close,
.poll = chcore_stdio_poll,
.ioctl = chcore_stdio_ioctl,
.fcntl = chcore_stdio_fcntl,
};
可以看到 stdout->write() 实际上就是调用的 chcore_stdout_write 函数。
This post is licensed under CC BY 4.0 by the author.