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