abbcb692b1f5f0e1b2890a7453d7beea762ecad6
[pintos-anon] / doc / tour.texi
1 @node Pintos Tour
2 @chapter A Tour Through Pintos
3
4 This chapter is a brief tour through the Pintos code.  It covers the
5 entire code base, but you'll only be using Pintos one part at a time,
6 so you may find that you want to read each part as you work on the
7 corresponding project.
8
9 @node Pintos Loading
10 @section Loading
11
12 This section covers the Pintos loader and basic kernel
13 initialization.
14
15 @node Pintos Loader
16 @subsection The Loader
17
18 The first part of Pintos that runs is the loader, in
19 @file{threads/loader.S}.  The PC BIOS loads the loader into memory.
20 The loader, in turn, is responsible for initializing the CPU, loading
21 the rest of Pintos into memory, and then jumping to its start.  It's
22 not important to understand exactly what the loader does, but if
23 you're interested, read on.  You should probably read along with the
24 loader's source.  You should also understand the basics of the
25 80@var{x}86 architecture as described by chapter 3 of
26 @bibref{IA32-v1}.
27
28 Because the PC BIOS loads the loader, the loader has to play by the
29 BIOS's rules.  In particular, the BIOS only loads 512 bytes (one disk
30 sector) into memory.  This is a severe restriction and it means that,
31 practically speaking, the loader has to be written in assembly
32 language.
33
34 Pintos' loader first initializes the CPU.  The first important part of
35 this is to enable the A20 line, that is, the CPU's address line
36 numbered 20.  For historical reasons, PCs start out with this address
37 line fixed at 0, which means that attempts to access memory beyond the
38 first 1 MB (2 raised to the 20th power) will fail.  Pintos wants to
39 access more memory than this, so we have to enable it.
40
41 Next, the loader asks the BIOS for the PC's memory size.  Again for
42 historical reasons, the function that we call in the BIOS to do this
43 can only detect up to 64 MB of RAM, so that's the practical limit that
44 Pintos can support.  The memory size is stashed away in a location in
45 the loader that the kernel can read after it boots.
46
47 Third, the loader creates a basic page table.  This page table maps
48 the 64 MB at the base of virtual memory (starting at virtual address
49 0) directly to the identical physical addresses.  It also maps the
50 same physical memory starting at virtual address
51 @code{LOADER_PHYS_BASE}, which defaults to @t{0xc0000000} (3 GB).  The
52 Pintos kernel only wants the latter mapping, but there's a
53 chicken-and-egg problem if we don't include the former: our current
54 virtual address is roughly @t{0x7c00}, the location where the BIOS
55 loaded us, and we can't jump to @t{0xc0007c00} until we turn on the
56 page table, but if we turn on the page table without jumping there,
57 then we've just pulled the rug out from under ourselves.  At any rate,
58 it's necessary.
59
60 After the page table is initialized, we load the CPU's control
61 registers to turn on protected mode and paging, and then we set up the
62 segment registers.  We aren't equipped to handle interrupts in
63 protected mode yet, so we disable interrupts.
64
65 Finally it's time to load the kernel from disk.  We choose a simple,
66 although inflexible, method to do this: we program the IDE disk
67 controller directly.  We assume that the kernel is stored starting
68 from the second sector of the first IDE disk (the first sector
69 contains the boot loader itself).  We also assume that the BIOS has
70 already set up the IDE controller for us.  We read
71 @code{KERNEL_LOAD_PAGES} 4 kB pages of data from the disk directly
72 into virtual memory starting @code{LOADER_KERN_BASE} bytes past
73 @code{LOADER_PHYS_BASE}, which by default means that we load the
74 kernel starting 1 MB into physical memory.
75
76 Then we jump to the start of the compiled kernel image.  Using the
77 ``linker script'' in @file{threads/kernel.lds.S}, the kernel has
78 arranged that it begins with the assembly module
79 @file{threads/start.S}.  This assembly module just calls
80 @code{main()}, which never returns.
81
82 There's one more trick to the loader: the Pintos kernel command line
83 is stored in the boot loader.  The @command{pintos} program actually
84 modifies the boot loader on disk each time it runs the kernel, putting
85 in whatever command line arguments the user supplies to the kernel,
86 and then the kernel at boot time reads those arguments out of the boot
87 loader in memory.  This is something of a nasty hack, but it is simple
88 and effective.
89
90 @node Kernel Initialization
91 @subsection Kernel Initialization
92
93 The kernel proper starts with the @code{main()} function.  The
94 @code{main()} function is written in C, as will be most of the code we
95 encounter in Pintos from here on out.
96
97 When @code{main()} starts, the system is in a pretty raw state.  We're
98 in protected mode with paging enabled, but hardly anything else is
99 ready.  Thus, the @code{main()} function consists primarily of calls
100 into other Pintos modules' initialization functions, which are
101 typically named @code{@var{module}_init()}, where @var{module} is the
102 module's name.
103
104 First we initialize kernel RAM in @code{ram_init()}.  The first step
105 is to clear out the kernel's so-called ``BSS'' segment.  The BSS is a
106 segment that should be initialized to all zeros.  In C, whenever you
107 declare a variable outside a function without providing an
108 initializer, that variable goes into the BSS.@footnote{This isn't
109 actually required by the ANSI C standard, but it is the case with most
110 implementations of C on most machines.}  Because it's all zeros, the
111 BSS isn't stored in the image that the loader brought into memory.  We
112 just use @code{memset()} to zero it out.  The other task of
113 @code{ram_init()} is to read out the machine's memory size from where
114 the loader stored it and put it into the @code{ram_pages} variable for
115 later use.
116
117
118
119 @node Threads Tour
120 @section Threads