Comments.
[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       tid_t tid;
124       printf ("\nExecuting '%s':\n", initial_program);
125       tid = process_execute (initial_program);
126 #ifdef THREAD_JOIN_IMPLEMENTED
127       if (tid != TID_ERROR)
128         thread_join (tid);
129 #endif
130     }
131 #else
132   /* Run the compiled-in test function. */
133   test ();
134 #endif
135
136   /* Finish up. */
137   if (power_off_when_done) 
138     power_off ();
139   else 
140     thread_exit ();
141 }
142 \f
143 /* Clear BSS and obtain RAM size from loader. */
144 static void
145 ram_init (void) 
146 {
147   /* The "BSS" is a segment that should be initialized to zeros.
148      It isn't actually stored on disk or zeroed by the kernel
149      loader, so we have to zero it ourselves.
150
151      The start and end of the BSS segment is recorded by the
152      linker as _start_bss and _end_bss.  See kernel.lds. */
153   extern char _start_bss, _end_bss;
154   memset (&_start_bss, 0, &_end_bss - &_start_bss);
155
156   /* Get RAM size from loader.  See loader.S. */
157   ram_pages = *(uint32_t *) ptov (LOADER_RAM_PAGES);
158 }
159
160 /* Populates the base page directory and page table with the
161    kernel virtual mapping, and then sets up the CPU to use the
162    new page directory.  Points base_page_dir to the page
163    directory it creates.
164
165    At the time this function is called, the active page table
166    (set up by loader.S) only maps the first 4 MB of RAM, so we
167    should not try to use extravagant amounts of memory.
168    Fortunately, there is no need to do so. */
169 static void
170 paging_init (void)
171 {
172   uint32_t *pd, *pt;
173   size_t page;
174
175   pd = base_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
176   pt = NULL;
177   for (page = 0; page < ram_pages; page++) 
178     {
179       uintptr_t paddr = page * PGSIZE;
180       void *vaddr = ptov (paddr);
181       size_t pde_idx = pd_no (vaddr);
182       size_t pte_idx = pt_no (vaddr);
183
184       if (pd[pde_idx] == 0)
185         {
186           pt = palloc_get_page (PAL_ASSERT | PAL_ZERO);
187           pd[pde_idx] = pde_create (pt);
188         }
189
190       pt[pte_idx] = pte_create_kernel (vaddr, true);
191     }
192
193   /* Store the physical address of the page directory into CR3
194      aka PDBR (page directory base register).  This activates our
195      new page tables immediately.  See [IA32-v2a] "MOV--Move
196      to/from Control Registers" and [IA32-v3] 3.7.5. */
197   asm volatile ("movl %0,%%cr3" :: "r" (vtop (base_page_dir)));
198 }
199
200 /* Parses the command line. */
201 static void
202 argv_init (void) 
203 {
204   char *cmd_line, *pos;
205   char *argv[LOADER_CMD_LINE_LEN / 2 + 2];
206   int argc = 0;
207   int i;
208
209   /* The command line is made up of null terminated strings
210      followed by an empty string.  Break it up into words. */
211   cmd_line = pos = ptov (LOADER_CMD_LINE);
212   printf ("Kernel command line:");
213   while (pos < cmd_line + LOADER_CMD_LINE_LEN)
214     {
215       ASSERT (argc < LOADER_CMD_LINE_LEN / 2);
216       if (*pos == '\0')
217         break;
218       argv[argc++] = pos;
219       printf (" %s", pos);
220       pos = strchr (pos, '\0') + 1;
221     }
222   printf ("\n");
223   argv[argc] = "";
224   argv[argc + 1] = "";
225
226   /* Parse the words. */
227   for (i = 0; i < argc; i++)
228     if (!strcmp (argv[i], "-rs")) 
229       random_init (atoi (argv[++i]));
230     else if (!strcmp (argv[i], "-d")) 
231       debug_enable (argv[++i]);
232     else if (!strcmp (argv[i], "-q"))
233       power_off_when_done = true;
234 #ifdef USERPROG
235     else if (!strcmp (argv[i], "-ex")) 
236       initial_program = argv[++i];
237     else if (!strcmp (argv[i], "-ul"))
238       user_page_limit = atoi (argv[++i]);
239 #endif
240 #ifdef FILESYS
241     else if (!strcmp (argv[i], "-f"))
242       format_filesys = true;
243     else if (!strcmp (argv[i], "-ci")) 
244       {
245         fsutil_copyin_file = argv[++i]; 
246         fsutil_copyin_size = atoi (argv[++i]); 
247       }
248     else if (!strcmp (argv[i], "-co"))
249       fsutil_copyout_file = argv[++i];
250     else if (!strcmp (argv[i], "-p")) 
251       fsutil_print_file = argv[++i];
252     else if (!strcmp (argv[i], "-r"))
253       fsutil_remove_file = argv[++i];
254     else if (!strcmp (argv[i], "-ls"))
255       fsutil_list_files = true;
256     else if (!strcmp (argv[i], "-D"))
257       fsutil_dump_filesys = true;
258 #endif
259     else if (!strcmp (argv[i], "-u"))
260       {
261         printf (
262           "Kernel options:\n"
263           " -rs SEED            Seed random seed to SEED.\n"
264           " -d CLASS[,...]      Enable the given classes of debug messages.\n"
265 #ifdef USERPROG
266           " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
267           " -ul USER_MAX        Limit user memory to USER_MAX pages.\n"
268 #endif
269 #ifdef FILESYS
270           " -f                  Format the filesystem disk (hdb or hd0:1).\n"
271           " -ci FILENAME SIZE   Copy SIZE bytes from the scratch disk (hdc\n"
272           "                     or hd1:0) into the filesystem as FILENAME\n"
273           " -co FILENAME        Copy FILENAME to the scratch disk, with\n"
274           "                     size at start of sector 0 and data afterward\n"
275           " -p FILENAME         Print the contents of FILENAME\n"
276           " -r FILENAME         Delete FILENAME\n"
277           " -ls                 List the files in the filesystem\n"
278           " -D                  Dump complete filesystem contents\n"
279 #endif
280           " -q                  Power off after doing requested actions.\n"
281           " -u                  Print this help message and power off.\n"
282           );
283         power_off ();
284       }
285     else 
286       PANIC ("unknown option `%s' (use -u for help)", argv[i]);
287 }
288
289 /* Powers down the machine we're running on,
290    as long as we're running on Bochs or qemu. */
291 void
292 power_off (void) 
293 {
294   const char s[] = "Shutdown";
295   const char *p;
296
297 #ifdef FILESYS
298   filesys_done ();
299 #endif
300
301   print_stats ();
302
303   printf ("Powering off...\n");
304   serial_flush ();
305
306   for (p = s; *p != '\0'; p++)
307     outb (0x8900, *p);
308   for (;;);
309 }
310
311 /* Print statistics about Pintos execution. */
312 static void
313 print_stats (void) 
314 {
315   timer_print_stats ();
316   thread_print_stats ();
317 #ifdef FILESYS
318   disk_print_stats ();
319 #endif
320   console_print_stats ();
321   kbd_print_stats ();
322 #ifdef USERPROG
323   exception_print_stats ();
324 #endif
325 }