Comments and a bit of initialization order cleanup.
[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 running requested actions? */
53 static bool do_power_off;
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 %'zd 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
109 #ifdef FILESYS
110   /* Initialize filesystem. */
111   disk_init ();
112   filesys_init (format_filesys);
113   fsutil_run ();
114 #endif
115
116   printf ("Boot complete.\n");
117   
118 #ifdef USERPROG
119   /* Run a user program. */
120   if (initial_program != NULL)
121     {
122       tid_t tid;
123       printf ("\nExecuting '%s':\n", initial_program);
124       tid = process_execute (initial_program);
125 #ifdef THREAD_JOIN_IMPLEMENTED
126       if (tid != TID_ERROR)
127         thread_join (tid);
128 #endif
129     }
130 #else
131   /* Run the compiled-in test function. */
132   test ();
133 #endif
134
135   /* Finish up. */
136   if (do_power_off) 
137     power_off ();
138   else 
139     thread_exit ();
140 }
141 \f
142 /* Clear BSS and obtain RAM size from loader. */
143 static void
144 ram_init (void) 
145 {
146   /* The "BSS" is a segment that should be initialized to zeros.
147      It isn't actually stored on disk or zeroed by the kernel
148      loader, so we have to zero it ourselves.
149
150      The start and end of the BSS segment is recorded by the
151      linker as _start_bss and _end_bss.  See kernel.lds. */
152   extern char _start_bss, _end_bss;
153   memset (&_start_bss, 0, &_end_bss - &_start_bss);
154
155   /* Get RAM size from loader.  See loader.S. */
156   ram_pages = *(uint32_t *) ptov (LOADER_RAM_PAGES);
157 }
158
159 /* Populates the base page directory and page table with the
160    kernel virtual mapping, and then sets up the CPU to use the
161    new page directory.  Points base_page_dir to the page
162    directory it creates.
163
164    At the time this function is called, the active page table
165    (set up by loader.S) only maps the first 4 MB of RAM, so we
166    should not try to use extravagant amounts of memory.
167    Fortunately, there is no need to do so. */
168 static void
169 paging_init (void)
170 {
171   uint32_t *pd, *pt;
172   size_t page;
173
174   pd = base_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
175   pt = NULL;
176   for (page = 0; page < ram_pages; page++) 
177     {
178       uintptr_t paddr = page * PGSIZE;
179       void *vaddr = ptov (paddr);
180       size_t pde_idx = pd_no (vaddr);
181       size_t pte_idx = pt_no (vaddr);
182
183       if (pd[pde_idx] == 0)
184         {
185           pt = palloc_get_page (PAL_ASSERT | PAL_ZERO);
186           pd[pde_idx] = pde_create (pt);
187         }
188
189       pt[pte_idx] = pte_create_kernel (vaddr, true);
190     }
191
192   asm volatile ("movl %0,%%cr3" :: "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], "-d")) 
226       debug_enable (argv[++i]);
227     else if (!strcmp (argv[i], "-q"))
228       do_power_off = true;
229 #ifdef USERPROG
230     else if (!strcmp (argv[i], "-ex")) 
231       initial_program = argv[++i];
232     else if (!strcmp (argv[i], "-ul"))
233       user_page_limit = atoi (argv[++i]);
234 #endif
235 #ifdef FILESYS
236     else if (!strcmp (argv[i], "-f"))
237       format_filesys = true;
238     else if (!strcmp (argv[i], "-ci")) 
239       {
240         fsutil_copyin_file = argv[++i]; 
241         fsutil_copyin_size = atoi (argv[++i]); 
242       }
243     else if (!strcmp (argv[i], "-co"))
244       fsutil_copyout_file = argv[++i];
245     else if (!strcmp (argv[i], "-p")) 
246       fsutil_print_file = argv[++i];
247     else if (!strcmp (argv[i], "-r"))
248       fsutil_remove_file = argv[++i];
249     else if (!strcmp (argv[i], "-ls"))
250       fsutil_list_files = true;
251     else if (!strcmp (argv[i], "-D"))
252       fsutil_dump_filesys = true;
253 #endif
254     else if (!strcmp (argv[i], "-u"))
255       {
256         printf (
257           "Kernel options:\n"
258           " -rs SEED            Seed random seed to SEED.\n"
259           " -d CLASS[,...]      Enable the given classes of debug messages.\n"
260 #ifdef USERPROG
261           " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
262           " -ul USER_MAX        Limit user memory to USER_MAX pages.\n"
263 #endif
264 #ifdef FILESYS
265           " -f                  Format the filesystem disk (hdb or hd0:1).\n"
266           " -ci FILENAME SIZE   Copy SIZE bytes from the scratch disk (hdc\n"
267           "                     or hd1:0) into the filesystem as FILENAME\n"
268           " -co FILENAME        Copy FILENAME to the scratch disk, with\n"
269           "                     size at start of sector 0 and data afterward\n"
270           " -p FILENAME         Print the contents of FILENAME\n"
271           " -r FILENAME         Delete FILENAME\n"
272           " -ls                 List the files in the filesystem\n"
273           " -D                  Dump complete filesystem contents\n"
274 #endif
275           " -q                  Power off after doing requested actions.\n"
276           " -u                  Print this help message and power off.\n"
277           );
278         power_off ();
279       }
280     else 
281       PANIC ("unknown option `%s' (use -u for help)", argv[i]);
282 }
283
284 /* Powers down the machine we're running on,
285    as long as we're running on Bochs or qemu. */
286 void
287 power_off (void) 
288 {
289   const char s[] = "Shutdown";
290   const char *p;
291
292 #ifdef FILESYS
293   filesys_done ();
294 #endif
295
296   print_stats ();
297
298   printf ("Powering off...\n");
299   serial_flush ();
300
301   for (p = s; *p != '\0'; p++)
302     outb (0x8900, *p);
303   for (;;);
304 }
305
306 /* Print statistics about Pintos execution. */
307 static void
308 print_stats (void) 
309 {
310   timer_print_stats ();
311   thread_print_stats ();
312 #ifdef FILESYS
313   disk_print_stats ();
314 #endif
315   console_print_stats ();
316   kbd_print_stats ();
317 #ifdef USERPROG
318   exception_print_stats ();
319 #endif
320 }