CS5460: Operating Systems Lecture 2: OS Hardware Interface (Chapter 2)
Course web page: http://www.eng.utah.edu/~cs5460/ CADE lab: WEB L224 and L226 http://www.cade.utah.edu/ Projects will be on Linux machines in CADE You don t need to go there, just ssh in Join the class mailing list Go to: https://sympa.eng.utah.edu/sympa/ So far 30 out of 61 have subscribed
Last Time OS History Mainframe era Minicomputer era PC era Ubiquitous era Basic OS principles apply over the entire 60-year history Concurrency Resource management Providing usable abstractions Hiding complexity Etc.
Operating System Organization
What is an Operating System? Interface between user and hardware Exports simpler virtual machine interface Hides ugly details of real hardware Manages shared resources CPU, memory, I/O devices, Ensure fairness Protect processes from one another Provides common services File system, VM, CPU scheduling, OS design reacts to HW changes What OS can do dictated by architecture Arch support (or lack thereof) can greatly simplify (of complicate) OS design Example: Early PCs, Motorola 68000 User Applications Operating System Hardware Virtual Machine Interface Physical Machine Interface
Modern OS Functionality 1 Provides a virtual processor for application code Clean up after an application when it finishes Applications are isolated from each other by default Can communicate (using the OS) when desired Concurrency Overlap I/O and computation even for a single thread Optionally, multiple threads even for a single processor Support running across multiple processors Manage I/O devices OS usually sees an asynchronous interface (initiate -> interrupt) OS usually provides a synchronous interface
Modern OS Functionality 2 Memory management Provides a virtual address space for each process Moves data between DRAM and disk OS decides how much memory each application gets Files Fast access to slow storage devices Coherence model Network OS provides a high-level interface to the Internet Security OS implements a security policy Other: Accounting, logging, error recovery,
Generic Computer Architecture CPU: ALUs, pipeline, LD/ST, Memory: virtual vs physical addrs System bus Split transaction, addr/data/io/cntl Separate interrupt lines Bus adapter Converts system bus à PCI/SCSI/ Device controllers CPU writes to mem-mapped IO regs Devices signal CPU via interrupts Things to consider: Interrupts and traps Memory-mapped I/O devices VA à PA translation DMA CPU Core RDs/WRs Memory Controller DRAM Interrupts Virtual addrs Trap I/O bus TLB/MMU Physical I/O bus adapter (e.g., PCI, SCSI) Disk ctlr Serial ctlr addrs Network controller L2$ L1$ tag tags System bus
OS Abstractions of HW Hardware Resource CPU Main memory Disk Network Devices OS abstraction Processes / Threads Address spaces File system Sockets / ports Virtual devices
HW Support for OS Abstractions OS Service Isolation between processes Virtual memory System calls Asynchronous I/O CPU scheduling / accounting Synchronization Hardware Support Kernel/user mode Protected instructions Memory management unit MMU / TLB Traps Interrupts / DMA Timer interrupts Atomic instructions Question: Which pieces of HW support are truly necessary?
Typical OS Structure User-level Applications Libraries: many common OS functions Example: malloc() vs sbrk() Kernel-level Top-level: machine independent Bottom-level: machine dependent Runs in protected mode Need a way to switch (user ß à kernel) Hardware-level Device maker exports known interface Device driver initiates operations by writing to device registers Devices use interrupts to signal completion DMA (offloads work, but has restrictions) User Apps Trap OS kernel I/O regs DMA Hardware Libs Direct manipulation Thrd File VM SIG CPU Disk Mem Int Interrupts DMA
Virtual Address Space (Simplified) Parts of the address space: Code: binary image of program Data/BSS: Static variables (globals) Heap: explicitly alloc d data (malloc) Stack: implicitly alloc d data I/O registers: not shown Huge unmapped areas exist, especially on 64-bit Small unmapped region around 0 Kernel mapped into all processes Question: How might we support shared libraries? MMU hardware: Remaps VAs to PAs Supports read-only, supervisor-only Detects accesses to unmapped regions Supervisor-only User mode 0xffffffff Read Only 0x80000000 Read Only 0x00000000 User stack segment User heap User data segment User code segment Kernel heap Kernel data segment Kernel code segment
Kernel Mode vs User Mode Some instructions can only be used in kernel mode Direct access to I/O devices (typically) Instructions to manipulate VAà PA mappings and TLB Enable/disable interrupts Halt the machine Architecture typically supports: Status bit in protected processor register indicating mode Restricts ability to perform certain instructions if not kernel mode How do user applications get access to protected instructions? Trap or interrupt à indirect jump via OS-managed function table System call typically implemented with special TRAP instruction
Anatomy of a System Call User applications make system calls to execute privileged instructions Anatomy of a system call: Program puts syscall params in registers Program executes a trap:» Minimal processor state (PC, PSW) pushed on stack» CPU switches mode to KERNEL» CPU vectors to registered trap handler in the OS kernel Trap handler uses param to jump to desired handler (e.g., fork, exec, open, ) When complete, reverse operation» Place return code in register» Return from exception foo: movl r1, (arg1) movl r0, #foo syscall syscallhdlr(){ switch (r0){ case: foo r0 ß foo( ); } asm( ret ); } User Kernel foo() { return res; }
System Calls Arguments passed in registers: (Why?) Integer constants (e.g., buffer size, file offset, fileid) Pointers to blocks of memory (e.g., strings, file buffers, ) Handles (e.g., file handle, socket handle, ) OS typically returns: Return code (value of 1 often denotes error) Other results written into buffers in user space You should always (always!) check syscall return values Principle: Dialogue between user-mode and kernel should be semantically simple Simpler interfaces easier to work with Simpler interfaces easier to implement correctly Simpler interfaces tend to be easier to make efficient
System Call Example Source void foo (void) { } write(1, hello\n, 6); Q: Where do all the magic numbers in the assembly come from? Note: For this class you will need to be able to read x86 and x86-64 assembly code Assembly Code <main>: pushq %rax mov $0x6,%edx mov $0x694010,%esi mov $0x1,%edi callq libc_write xorl %eax,%eax popq %rdx ret <libc_write>: mov $0x1,%eax syscall cmp $0xfffffffffffff001,%rax jae < syscall_error> retq
Traps Architecture detects special events: trap instruction invalid memory access floating point exception privileged instruction by user mode code When processor detects condition: Save minimal CPU state (PC, sp, ) done by hardware Switches to KERNEL mode Transfers control to trap handler» Indexes trap table w/ trap number» Jumps to address in trap table (*)» Handler saves more state and may disable interrupts RTE instruction reverses operation TRAP VECTOR: 0x0082404 Illegal address 0x0084d08 Mem Violation 0x008211c Illegal instruction 0x0082000 System call Here, 0x82404 is address of handle_illegal_addr().
Important from Today HW provides support for OS abstractions Make them possible to implement Make them easier to implement Make them more efficient User programs run in processes Each see its own virtual address space Kernel has a very different view of memory Modern processors support (at least) two modes User mode and kernel mode The kernel is not a process User programs trap into kernel mode to access OS functionality