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