Get rid of DEBUG macro, supporting code, and documentation,
[pintos-anon] / src / threads / init.c
1 #include "threads/init.h"
2 #include <console.h>
3 #include <debug.h>
4 #include <limits.h>
5 #include <random.h>
6 #include <stddef.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "devices/kbd.h"
12 #include "devices/serial.h"
13 #include "devices/timer.h"
14 #include "devices/vga.h"
15 #include "threads/interrupt.h"
16 #include "threads/io.h"
17 #include "threads/loader.h"
18 #include "threads/malloc.h"
19 #include "threads/mmu.h"
20 #include "threads/palloc.h"
21 #include "threads/test.h"
22 #include "threads/thread.h"
23 #ifdef USERPROG
24 #include "userprog/process.h"
25 #include "userprog/exception.h"
26 #include "userprog/gdt.h"
27 #include "userprog/syscall.h"
28 #include "userprog/tss.h"
29 #endif
30 #ifdef FILESYS
31 #include "devices/disk.h"
32 #include "filesys/filesys.h"
33 #include "filesys/fsutil.h"
34 #endif
35
36 /* Amount of physical memory, in 4 kB pages. */
37 size_t ram_pages;
38
39 /* Page directory with kernel mappings only. */
40 uint32_t *base_page_dir;
41
42 #ifdef FILESYS
43 /* -f: Format the filesystem? */
44 static bool format_filesys;
45 #endif
46
47 #ifdef USERPROG
48 /* -ex: Initial program to run. */
49 static char *initial_program;
50 #endif
51
52 /* -q: Power off after kernel tasks complete? */
53 bool power_off_when_done;
54
55 static void ram_init (void);
56 static void paging_init (void);
57 static void argv_init (void);
58 static void print_stats (void);
59
60 int main (void) NO_RETURN;
61
62 int
63 main (void)
64 {
65   /* Clear BSS and get machine's RAM size. */  
66   ram_init ();
67
68   /* Initialize ourselves as a thread so we can use locks. */
69   thread_init ();
70
71   /* Initialize the console so we can use printf(). */
72   vga_init ();
73   serial_init_poll ();
74   console_init ();
75
76   /* Greet user. */
77   printf ("Pintos booting with %'zu kB RAM...\n", ram_pages * PGSIZE / 1024);
78
79   /* Parse command line. */
80   argv_init ();
81
82   /* Initialize memory system. */
83   palloc_init ();
84   malloc_init ();
85   paging_init ();
86
87   /* Segmentation. */
88 #ifdef USERPROG
89   tss_init ();
90   gdt_init ();
91 #endif
92
93   /* Set random seed if argv_init() didn't. */
94   random_init (0);
95
96   /* Initialize interrupt handlers. */
97   intr_init ();
98   timer_init ();
99   kbd_init ();
100 #ifdef USERPROG
101   exception_init ();
102   syscall_init ();
103 #endif
104
105   /* Start thread scheduler and enable interrupts. */
106   thread_start ();
107   serial_init_queue ();
108   timer_calibrate ();
109
110 #ifdef FILESYS
111   /* Initialize filesystem. */
112   disk_init ();
113   filesys_init (format_filesys);
114   fsutil_run ();
115 #endif
116
117   printf ("Boot complete.\n");
118   
119 #ifdef USERPROG
120   /* Run a user program. */
121   if (initial_program != NULL)
122     {
123       printf ("\nExecuting '%s':\n", initial_program);
124       process_wait (process_execute (initial_program));
125     }
126 #else
127   /* Run the compiled-in test function. */
128   test ();
129 #endif
130
131   /* Finish up. */
132   if (power_off_when_done) 
133     power_off ();
134   else 
135     thread_exit ();
136 }
137 \f
138 /* Clear BSS and obtain RAM size from loader. */
139 static void
140 ram_init (void) 
141 {
142   /* The "BSS" is a segment that should be initialized to zeros.
143      It isn't actually stored on disk or zeroed by the kernel
144      loader, so we have to zero it ourselves.
145
146      The start and end of the BSS segment is recorded by the
147      linker as _start_bss and _end_bss.  See kernel.lds. */
148   extern char _start_bss, _end_bss;
149   memset (&_start_bss, 0, &_end_bss - &_start_bss);
150
151   /* Get RAM size from loader.  See loader.S. */
152   ram_pages = *(uint32_t *) ptov (LOADER_RAM_PAGES);
153 }
154
155 /* Populates the base page directory and page table with the
156    kernel virtual mapping, and then sets up the CPU to use the
157    new page directory.  Points base_page_dir to the page
158    directory it creates.
159
160    At the time this function is called, the active page table
161    (set up by loader.S) only maps the first 4 MB of RAM, so we
162    should not try to use extravagant amounts of memory.
163    Fortunately, there is no need to do so. */
164 static void
165 paging_init (void)
166 {
167   uint32_t *pd, *pt;
168   size_t page;
169
170   pd = base_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
171   pt = NULL;
172   for (page = 0; page < ram_pages; page++) 
173     {
174       uintptr_t paddr = page * PGSIZE;
175       void *vaddr = ptov (paddr);
176       size_t pde_idx = pd_no (vaddr);
177       size_t pte_idx = pt_no (vaddr);
178
179       if (pd[pde_idx] == 0)
180         {
181           pt = palloc_get_page (PAL_ASSERT | PAL_ZERO);
182           pd[pde_idx] = pde_create (pt);
183         }
184
185       pt[pte_idx] = pte_create_kernel (vaddr, true);
186     }
187
188   /* Store the physical address of the page directory into CR3
189      aka PDBR (page directory base register).  This activates our
190      new page tables immediately.  See [IA32-v2a] "MOV--Move
191      to/from Control Registers" and [IA32-v3] 3.7.5. */
192   asm volatile ("mov %%cr3, %0" :: "r" (vtop (base_page_dir)));
193 }
194
195 /* Parses the command line. */
196 static void
197 argv_init (void) 
198 {
199   char *cmd_line, *pos;
200   char *argv[LOADER_CMD_LINE_LEN / 2 + 2];
201   int argc = 0;
202   int i;
203
204   /* The command line is made up of null terminated strings
205      followed by an empty string.  Break it up into words. */
206   cmd_line = pos = ptov (LOADER_CMD_LINE);
207   printf ("Kernel command line:");
208   while (pos < cmd_line + LOADER_CMD_LINE_LEN)
209     {
210       ASSERT (argc < LOADER_CMD_LINE_LEN / 2);
211       if (*pos == '\0')
212         break;
213       argv[argc++] = pos;
214       printf (" %s", pos);
215       pos = strchr (pos, '\0') + 1;
216     }
217   printf ("\n");
218   argv[argc] = "";
219   argv[argc + 1] = "";
220
221   /* Parse the words. */
222   for (i = 0; i < argc; i++)
223     if (!strcmp (argv[i], "-rs")) 
224       random_init (atoi (argv[++i]));
225     else if (!strcmp (argv[i], "-q"))
226       power_off_when_done = true;
227 #ifdef USERPROG
228     else if (!strcmp (argv[i], "-ex")) 
229       initial_program = argv[++i];
230     else if (!strcmp (argv[i], "-ul"))
231       user_page_limit = atoi (argv[++i]);
232 #endif
233 #ifdef FILESYS
234     else if (!strcmp (argv[i], "-f"))
235       format_filesys = true;
236     else if (!strcmp (argv[i], "-ci")) 
237       {
238         fsutil_copyin_file = argv[++i]; 
239         fsutil_copyin_size = atoi (argv[++i]); 
240       }
241     else if (!strcmp (argv[i], "-co"))
242       fsutil_copyout_file = argv[++i];
243     else if (!strcmp (argv[i], "-p")) 
244       fsutil_print_file = argv[++i];
245     else if (!strcmp (argv[i], "-r"))
246       fsutil_remove_file = argv[++i];
247     else if (!strcmp (argv[i], "-ls"))
248       fsutil_list_files = true;
249     else if (!strcmp (argv[i], "-D"))
250       fsutil_dump_filesys = true;
251 #endif
252     else if (!strcmp (argv[i], "-u"))
253       {
254         printf (
255           "Kernel options:\n"
256           " -rs SEED            Set random seed to SEED.\n"
257 #ifdef USERPROG
258           " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
259           " -ul USER_MAX        Limit user memory to USER_MAX pages.\n"
260 #endif
261 #ifdef FILESYS
262           " -f                  Format the filesystem disk (hdb or hd0:1).\n"
263           " -ci FILENAME SIZE   Copy SIZE bytes from the scratch disk (hdc\n"
264           "                     or hd1:0) into the filesystem as FILENAME\n"
265           " -co FILENAME        Copy FILENAME to the scratch disk, with\n"
266           "                     size at start of sector 0 and data afterward\n"
267           " -p FILENAME         Print the contents of FILENAME\n"
268           " -r FILENAME         Delete FILENAME\n"
269           " -ls                 List the files in the filesystem\n"
270           " -D                  Dump complete filesystem contents\n"
271 #endif
272           " -q                  Power off after doing requested actions.\n"
273           " -u                  Print this help message and power off.\n"
274           );
275         power_off ();
276       }
277     else 
278       PANIC ("unknown option `%s' (use -u for help)", argv[i]);
279 }
280
281 /* Powers down the machine we're running on,
282    as long as we're running on Bochs or qemu. */
283 void
284 power_off (void) 
285 {
286   const char s[] = "Shutdown";
287   const char *p;
288
289 #ifdef FILESYS
290   filesys_done ();
291 #endif
292
293   print_stats ();
294
295   printf ("Powering off...\n");
296   serial_flush ();
297
298   for (p = s; *p != '\0'; p++)
299     outb (0x8900, *p);
300   for (;;);
301 }
302
303 /* Print statistics about Pintos execution. */
304 static void
305 print_stats (void) 
306 {
307   timer_print_stats ();
308   thread_print_stats ();
309 #ifdef FILESYS
310   disk_print_stats ();
311 #endif
312   console_print_stats ();
313   kbd_print_stats ();
314 #ifdef USERPROG
315   exception_print_stats ();
316 #endif
317 }