第一个进程
第一个进程的产生
Xv6执行指令时的3种模式:
-
machine mode
-
supervisor mode
-
user mode
CPUs provide a special instruction that switches the CPU from user mode to supervisor mode and enters the kernel at an entry point specified by the kernel.(RISC-V provides the ecall instruction for this purpose.) Once the CPU has switched to supervisor mode, the kernel can then validate the arguments of the system call(e.g.,check if the address passed to the system call is part of the application’s memory),decide whether the application is allowed to perform the requested operation(e.g., check if the applications is allowed to write the specified file), and then deny it or execute it. It is important that the kernel control the kernel entry point, a malicious application could, for example, enter the kernel at a point where the validation of arguments is skipped.
The mechanisms used by the kernel to implement processes include the user/supervisor mode flag, address spaces, and time-slicing of threads.
进程的虚拟内存分布

An address space includes the process’s user memory starting at virtual address zero. Instructions come first, followed by global variables, then stack, and finally a “heap” area(for malloc) that the process can expand as needed.
There are a number of factors that limit the maximum size of a process’s address space: pointers on the RISC-V are 64 bits wide; the hardware only uses the low 39 bits. Thus, the maximum address is $2^{38} - 1 = 0×3FFFFFFFFF$,which is MAXVA. At the top of the address space xv6 reserves a page for trampoline and a page mapping the process’s trapframe. Xv6 uses these two pages to transition in and out of the kernel and mapping thetrapframe is necessary to save/restore the state of the user process.
- xv6进程的状态信息存储在
struct proc - A process can make a system call by executing the RISC-V
ecallinstruction. This instruction raises the hardware privilege level and changes the program counter to a kernel-defined entry point. The code at the entry point switches to a kernel stack and executes the kernel instructions that implement the system call. - When the system call completes, the kernel switches back to the user stack and returns to user space by calling
sretinstruction, which lowers the hardware privilege level and resumes executing user instructions just after the system call instruction. - A process’s thread can “block” in the kernel to wait for I/O, and resume where it left off when the I/O has finished
p->stateindicates whether the process is allocated, ready to run, running, waiting for I/O, or exiting.p->pagetableholds the process’s page table, in the format that the RISC-V hardware expects. Xv6 causes the paging hardware to use a process’sp->pagetablewhen executing that process in user space. A process’s page table also serves as the record of the address of the physical pages allocated to store the process’s memory.
The first process and system call
- The bootloader loads the xv6 kernel into memory(then, in machine mode the CPU executes xv6 starting at
_entrywith paging hardware disabled: virtual addresses map directly to physical address) _entrydeclares space for an initial stack,stack0in the filestart.c. The code at_entryloads stack pointerspwith the addressstack0 + 4096. Then_entrycalls into C code atstartstartfunction performs some configurations then switches to supervisor mode(it sets the previous privilege mode to super in the registermstatus, it sets the return address tomainby writing main’s address into the page-table registersatp, and delegates all interrupts and exceptions to supervisor mode)- Before jumping into supervisor mode,
startperforms one more task: it programs the clock chip to generate timer interrupts. Thenstart“returns” to supervisor mode by callingmret. This causes the program counter to change tomain. - Then
maininitializes serval devices and subsystems, it creates the first process byuserinit. - The first process executes a small program written in RISC-V assembly.
initcode.S(user/initcode.S:3) loads the number for the exec system call, SYS_EXEC (kernel/syscall.h:8), into register a7, and then callsecallto re-enter the kernel. - The kernel uses the number in register a7 in
syscall(kernel/syscall.c:133) to call the desired system call. The system call table (kernel/syscall.c:108) mapsSYS_EXECto sys_exec, which the kernel invokes.