Appendix A: PC hardware
- Processor and memory
Appendix B: The boot loader
The BIOS loads the boot sector at memory address 0x7c00 and then jumps (sets the processor’s %ip) to that address.
When the boot loader begins executing, the processor is simulating an Intel 8088, and the loader’s job is to put the processor in a more modern operating mode, to load the xv6 kernel from disk into memory, and then to transfer control to the kernel.
Code: Assembly bootstrap
- disable interrupts
- set up the important data segment registers (DS, ES, SS)
- enable the 21st address bit using I/O to the keyboard controller on ports 0x64 and 0x60
- enables protected mode and 32-bit mode
- first action in 32-bit mode is to initialize the data segment registers
- set up a stack in an unused region of memory
- calls the C function bootmain
For historical reasons we have used the term virtual address to refer to addresses manipulated by programs. An xv6 virtual address is the same as an x86 logical address.
And in xv6, the logical address is equal to the linear address to which the segmentation hardware maps it.
xv6 makes almost no use of segments; it uses the paging hardware instead, as Chapter 2 describes. The boot loader sets up the segment descriptor table gdt so that all segments have a base address of zero.
When the boot loader is processing, the linear address is equal to the physical address, without paging hardware enabled.
Once the kernel starts executing, it will set up the paging hardware.
Code: C bootstrap
- copy the kernel executable which starting at the second sector to address 0x10000
- check that this probably is an ELF binary, and not an uninitialized disk
- call the kernel’s entry point
the kernel has been compiled and linked so that it expects to find itself at virtual addresses starting at 0x80100000.
Once the kernel starts executing, it will set up the paging hardware to map virtual addresses starting at 0x80100000 to physical addresses starting at 0x00100000.
In real world, kernels are stored in ordinary file systems, where they may not be contiguous, or are loaded over a network. These complications require the boot loader to be able to drive a variety of disk and network controllers and understand various file systems and network protocols.
In other words, the boot loader itself must be a small operating system.
Therefore, PC operating systems often use a two-step boot process.
- First, a simple boot loader like the one in this appendix loads a full-featured boot-loader from a known disk location, often relying on the less space-constrained BIOS for disk access rather than trying to drive the disk itself.
- Then the full loader, relieved of the 512-byte limit, can implement the complexity needed to locate, load, and execute the desired kernel.
However, Modern PCs avoid many of the above complexities, because they support the Unified Extensible Firmware Interface (UEFI), which allows the PC to read a larger boot loader from the disk (and start it in protected and 32-bit mode).
- Stored program computer
- Memory-mapped I/O
- Software = hardware
- PC architecture
- x86 instruction set
- gcc calling conventions
- PC emulation