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