xv6-七
前言这篇博客研究xv6的进程调度机制的实现
多进程现代操作系统基本都支持并行多进程(多CPU多进程),而要实现该功能,需要解决如下问题
如何切换进程?虽然实现思路不是很难,但是实现细节比较复杂。
如何对用户进程透明?即用户进程应该对于进程切换无感——进程切换前和进程切换后,进程的上下文不应有任何改变
如何找到当前CPU执行的进程的描述符?进程可能被切换到任何CPU上,则CPU应当可以高效的找到当前执行的进程的描述符信息,从而在S-mode时更改当前进程的状态信息
进程切换xv6的进程切换的基本流程如下图所示
可以看到,xv6实现进程切换的方式非常标准——首先从U-mode陷入到S-mode(系统调用或中断),再从对应的S-mode切换到CPU切换进程(每个CPU在操作系统初始化时的执行流)。
接着就是上述步骤的反向操作,即切换到调度出的待切换进程的S-mode,然后从S-mode返回到U-mode,最终完成进程切换
进程调度时,进程首先陷入到S-mode,根据前面xv6-二可知,U-mode的上下文会保存在S-mode的内核栈中;当进程切换结束时,会从S-mode返回到U-mode ...
xv6-六
前言这篇博客研究xv6的Copy-on-Write机制的实现
Lab Copy-on-Write Fork for xv6本次lab用来实现xv6的Copy-on-Write机制
Copy-on-Write要求
Your task is to implement copy-on-write fork in the xv6 kernel. You are done if your modified kernel executes both the cowtest and usertests programs successfully.
分析Copy-on-Write和lazy allocation非常类似,都是为了节省直接分配导致的性能损失,从而推迟实际的physical page的分配和映射,仅仅完成virtual page的分配。
其中,Copy-on-Write是在进程fork时,仅仅复制父进程的pd(页表),而共享实际的physical page,从而节省了physical page的分配和内容的复制。而实际的页框(physical page)分配,延迟到父进程或子进程执行 ...
xv6-五
前言这篇博客研究lazy page allocation机制
lazy page allocation一个操作系统中可以包含多个进程,进程的地址空间所占用的虚拟地址空间之和一般远远大于实际的物理内存之和。
因此,一般操作系统通过通过如下几种方法,将进程的超大的虚拟地址空间映射到有限的物理地址空间中
不同虚拟内存映射相同物理内存实际上,不同进程或相同进程的不同虚拟内存有很大一部分包含相同的数据(linux的glibc库, 内核的stack0数据)。因此,完全可以将这些虚拟内存指向相同的物理地址
延迟分配往往进程会申请超过实际需要的内存,并且申请后不会立即使用。因此,当进程申请内存时,仅仅分配虚拟内存并记录在描述符中,但是并不实际分配物理内存并映射。也就是此时并不消耗物理内存。当进程真正访问该虚拟内存时,会产生page fault,从而在异常处理时完成实际的映射即可
Lab lazy allocation本次lab帮助熟悉xv6的lazy allocation机制
Lazy allocation要求
Modify the code in trap.c to respond to a p ...
xv6-四
前言这篇博客探索一下xv6从U-mode地址空间trap(陷入)到S-mode地址空间的机制(前面xv6-二已经介绍的非常详细了)
Lab traps本次lab帮助熟悉xv6的trap(陷入)机制
Backtrace要求
Implement a backtrace() function in kernel/printf.c. Insert a call to this function in sys_sleep, and then run bttest, which calls sys_sleep. Your output should be as follows:
1234backtrace:0x0000000080002cda0x0000000080002bb60x0000000080002898
After bttest exit qemu. In your terminal: the addresses may be slightly different but if you run addr2line -e kernel/kernel (or riscv64-unknown- ...
xv6-三
前言这篇博客探索一下xv6内核的虚拟内存机制
xv6的页表机制page table(页表)是典型的软、硬件结合的机制,即硬件提供相关的电路实现和接口,操作系统根据硬件的接口,实现相关的服务
页表硬件对于riscv指令来说(无论在S-mode还是U-mode),其操作的是virtual address(虚拟地址)。但是对于机器的RAM来说,其操作的是physical address(物理地址)
而page table的硬件部分,则是连接两个地址的组件——其将virtual address(虚拟地址)映射为physical address(物理地址)
page table工作的基本逻辑如下图所示
直白的说,其将虚拟地址空间和物理地址空间以页(4096字节)为单位切分,并以页为单位进行映射(即通过page table记录页号之间的映射关系)
当然,riscv支持多种page table机制,但是这些机制的大体思路和上面的图所展示的是一致的
xv6采用了Sv39方案的page table,即support a 39-bit virtual address space。该方案中,64bit的vi ...
xv6-二
前言这篇博客探索一下xv6内核的系统调用过程
xv6启动流程参考xv6-book,可以对xv6的启动过程有非常清晰的认识,这对于理解linux内核的启动大有裨益
首先,写在ROM中的boot loader,将内核装载入内存中,并将执行流跳转到固定的入口点(代码写死在ROM中,自然跳转的入口点也是固定的)
因此,编译内核时,需要将内核的入口函数_entry(kernel/entry.S:6)编译到boot loader指定的地址处(xv6是0x80000000)
而为了让生活更美好,_entry函数使用汇编指令初始化栈后,跳转到使用C语言编写的start(kernel/start.c:20)。start函数的主要工作就是设置CSRs(control and state registers),从而切换到S-mode(supervisor mode),并将执行流设置成main(kernel/main.c:10)。start函数实现的非常巧妙,其通过设置CSRs,伪造一个异常处理保存的上下文,其上下文的特权级是S-mode,PC是main。执行mret指令后,通过恢复上下文,完成特权级和执行流 ...