Instruction-execution cycle: 1) Fetch from memory. 2) Decode into base instructions (morphemes) and execute in sequence. 3) Each causes loading from and storing to specific memory addresses. 4) Results, if any, stored back in memory. Essentially, the MMU sees only a stream of memory addresses (instruction OR data), it does not know how they are generated. This is the "data structure" to the CPU's "algorithm." The only storage that the CPU can access directly are: Main memory -- DRAM, etc. Registers -- on the CPU. Cache -- accomodates speed difference between main memory (X cycles) & registers (1 cycle). Real mode -- direct access to hardware and BIOS routines; only 1MB addressable. Protected mode -- utilizes memory management registers to provide hardware-level memory protection and task management. * Paging. * Virtual memory. * Segmentation. Virtual 8086 mode -- in protected mode, simulates real mode for real mode applications (eg. DOS in Windows). ========================[ BOOTSTRAP - initialize to known state ]========================= We have a black box with an %eip that increments, executing instructions which mutate memory. But how does it "read" the kernel from the file system? 1) Hardware always fetches first instruction from 0xFFFF0, which contains a jump to the BIOS entry point. 2) BIOS configures hardware details, power on self test (POST), loads boot sector (code from kernel) to 0x7C00 and points %eip to it. 3) Boot loader (GRUB) loads in an operating system from a "portable kernel format" located in the first 8 kilobytes. Imagine ELF executable fields. 4) Operating system <_start> needs to install 3 descriptors into GDT to enter protected mode. * Null descriptor. * Kernel code descriptor. * Kernel data descriptor. 5) We have a known state. Load in TSS and IDT. * Now we have hardware protection of memory, addressing the full 4GB range. * By contract, initial kernel stack starts at top of kernel heap. Initial kernel code farther down. ========================[ KERNEL - run user programs ]========================= We've covered the hardware part of creating a "system" that can run "programs". Now WE need to provide the software part. * Assemble machine parts into process parts: - [vm.c] Virtual memory from physical memory. - [loader.c] Memory image from executable/image file. - [t/pcb.c] Process from memory, registers, memory images. * Share a machine among processes; share a process among threads. - [scheduler.c] Context switch and yield. - [registrar.c] Sleep voluntarily, for shared devices, resources, etc. Loading: 1) Linker merges multiple relocatable object files (.o) to an image file (aka executable object file). Resolves dependencies and relocates relative symbols to absolute locations. 2) Loader converts executable file (ELF) into memory image. * Decides on "entry point", "top of the ustack, kstack", etc. * Sets program counter to entry point. * Sets stack pointer to top of stack. * Control structures -- tCB, TCB... * Virtual memory -- provides the functionality of swapping in different address spaces upon context switching. * Scheduler -- manages the process of context switching.