As a user: it's occasionally good to know how abstractions are implemented so that you can reason about them. For example, reasoning about performance and security both require understanding of underlying system.
As a system designer: Operating systems are always changing to adapt to new hardware and differing requirements: you may find yourself hacking on one at some point.
See "A short history of Operating Systems" in the 2017sp slides.
The OS is software that mediates the interactions between applications and hardware. It provides:
Abstraction: a common interface to many devices so that applications don't need to be written for specific devices, and don't need to worry about low-level details.
Virtualization: gives multiple applications the illusion that they have complete control over resources (such as the CPU, I/O devices, and memory) despite the fact that they are shared and limited.
Isolation: prevents untrusted applications from interfering with each other
Access control: allow untrusted applications to have access to resources in a controlled way.
Suppose we just finished our architecture course and had a design for a processor and memory. How would we implement a program that takes input from a keyboard?
Note: This is not the final picture, we will continue the discussion tomorrow, but here's where we left off:
To start with, we need the keyboard itself. We can think of this as a collection of switches (one for each key). These are connected to an encoder; when a key is pressed, a collection of wires encoding the key code is activated. The hardware that operates a device is called the device controller.
The interesting question is what happens next. What do we do with those signals? How do they make their way to the processor and ultimately the program?
We came up with two designs for the actual connection between the keyboard and the processor:
Our first idea was to have a dedicated I/O bus. The keyboard (and other devices) are connected to the bus. The instruction set has dedicated instructions for interfacing with this bus. This design is called programmed I/O.
Our second idea (and one that is more commonly used) is to connect the devices directly to the memory bus. Each device has a specific range of physical addresses allocated to it; the address lines of the bus determine whether the data and r/w lines are connected to main memory or to the device. To read data from the keyboard, the processor issues a read instruction to the address corresponding to the keyboard. This scheme is called memory mapped I/O because the device is mapped into the physical address space. Note that devices do not directly access memory (this is DMA, which we will discuss next time).
In either of these two designs, when a key is pressed, the keycode will be stored by the device, and an interrupt will be raised (on the interrupt line, which connects the device to the interrupt controller).
This will cause the CPU should jump to the address of some device-specific code, called the device driver, using the device ID to determine which driver to jump to. Tomorrow we will refine this picture somewhat: in fact the processor will jump to the operating system's interrupt service routine, which may in turn jump to the driver.
At any rate, the driver will then use the I/O instructions (if using programmed I/O) or load and store instructions (if using memory-mapped I/O) to do the appropriate thing. More discussion on what "the appropriate thing" is coming soon.