OS Organization
Last updated
Last updated
OS must arrange for isolation between the processes. If one process has a bug and fails, it shouldn’t affect others that don’t depend on the failed process.
An operating system must fulfill three requirements: multiplexing, isolation, and interaction.
Abstracting physical resources.
CPUs provide hardware support for strong isolation. For example, RISC-V has three modes in which the CPU can execute instructions: machine mode, supervisor mode, and user mode.
Instructions executing in machine mode have full privilege; a CPU starts in machine mode. Machine mode is mostly intended for configuring a computer.
In supervisor mode the CPU is allowed to execute privileged instructions: for example, enabling and disabling interrupts, reading and writing the register that holds the address of a page table, etc.
An application can execute only user-mode instructions.
An application that wants to invoke a kernel function (e.g., the read system call in xv6) must transition to the kernel. 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.)
Kernel control the entry point for transitions to supervisor mode for security reasons.
The unit of isolation in xv6 is a process.
Xv6 runs on RISC-V with 39 bits for virtual addresses, but uses only 38 bits. Thus, the maximum address is 2 38 − 1 = 0x3fffffffff, which is MAXVA (kernel/riscv.h:349).
Each process has a thread of execution (or thread for short) that executes the process’s instructions. A thread can be suspended and later resumed. To switch transparently between processes, the kernel suspends the currently running thread and resumes another process’s thread (context switch).
When the RISC-V computer powers on, it initializes itself and runs a boot loader which is stored in read-only memory. The boot loader loads the xv6 kernel into memory. Then, in machine mode, the CPU executes xv6 starting at _entry (kernel/entry.S:12). Xv6 starts with the RISC-V paging hardware disabled: virtual addresses map directly to physical addresses.
The boot loader loads the xv6 kernel into memory at physical address 0x80000000, because the address range 0x0:0x80000000 contains I/O devices.
The instructions at _entry set up a stack so that xv6 can run C code. The code at _entry loads the stack pointer register sp with the address stack0+4096
, the top of the stack, because the stack on RISC-V grows down.
Now xv6 has a stack, and able to run C code.
_entry calls into C code at start (kernel/start.c:21).
Perform some configurations that is only allowed in machine mode.
Set Program Counter to main
.
Disable paging by set satp
to 0.
Enable clock interrupts.
Switch to supervisor mode and jump to main()
.
In main
, after initializes several devices and subsystems, it creates the first process by calling userinit
.
The 1st process executes a small program: initcode
. In code, we have
The above is the octal data format of the binary built from initcode.S
.
initcode.S
:
The above initcode
program re-enters kernel by invoking exec
system call to run a new program init
.
The init
:
This program creates file descriptors 0, 1, 2. Start a console shell. Wait for shell exists, and repeat.
Now the system is up!