本章主要描述进程、线程和上下文切换相关内容。
1. vmspace
每个进程都需要有自己的虚拟地址空间,这个虚拟地址空间用vmspace来描述。
1 | struct vmspace { |
- 虚拟地址空间翻译需要有页表基地址,vmspace中的pgtbl就是该进程的页表基地址
- 一个vmspace可能由多个vmregion组成,因此使用链表进行管理
1.1 初始化
1 |
|
- 分配root页表页
- 指定用户栈的地址
1.2 内存映射
假设我们已经分配好了一个物理内存对象(pmo),我们需要将虚拟地址和物理地址进行映射。
1 | int vmspace_map_range(struct vmspace *vmspace, vaddr_t va, size_t len, |
- 分配vmregion对象
- vmr添加到vmspace中,就是添加到链表中
- 调用
fill_page_table()
填充页表,这是内核提供的page_table的相关函数(参考memory章节)
1.3 内存去映射
1 | int vmspace_unmap_range(struct vmspace *vmspace, vaddr_t va, size_t len) |
1.4 切换虚拟地址空间
不同的进程使用不同的虚拟地址空间,切换虚拟地址空间就是设置pgtbl到ttbr0_el1寄存器即可。
1 | void switch_vmspace_to(struct vmspace *vmspace) |
2 capability
ChChor基于capability对内核资源进行访问控制。
所有内核资源(如物理内存等)均被抽象为了内核对象。应用通过整型的标识符cap访问从属于该进程的内核对象。
capability的代码不复杂,这里不分析代码了,主要是理解它的数据结构的设计。
- 真正的内核对象用object进行表示,一个object就是一个内核对象
- 内核对象的obj,藏在object->opaque中,它可以是物理内存,也可以是其他
- 一个object可以被多个进程共享,因此,object->copies_head就是用来把所有引用了该对象的object_slot用链表管理起来
- 一个进程所有的内核对象是通过slot_table进行管理的,它是一个数组,用bitmap标识,一个数组元素指向一个object_slot
- 通过slot_id即可找到该进程的内核对象
3 process
4 thread
5 跳转到thread执行
1 | void main(void *addr) |
1 | u64 switch_context(void) |
1 | BEGIN_FUNC(eret_to_thread) |