b98e580feab1e59eae30775fd62f696cd2bd3f10
[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 "devices/partition.h"
33 #include "filesys/filesys.h"
34 #include "filesys/fsutil.h"
35 #endif
36
37 /* Page directory with kernel mappings only. */
38 uint32_t *base_page_dir;
39
40 #ifdef FILESYS
41 /* -f: Format the file system? */
42 static bool format_filesys;
43 #endif
44
45 #ifdef USERPROG
46 /* -ex: Initial program to run. */
47 static char *initial_program;
48 #endif
49
50 /* -q: Power off after kernel tasks complete? */
51 bool power_off_when_done;
52
53 static void ram_init (void);
54 static void paging_init (void);
55 static void argv_init (void);
56 static void print_stats (void);
57
58 int main (void) NO_RETURN;
59
60 int
61 main (void)
62 {
63   /* Clear BSS and get machine's RAM size. */  
64   ram_init ();
65
66   /* Initialize ourselves as a thread so we can use locks. */
67   thread_init ();
68
69   /* Initialize the console so we can use printf(). */
70   vga_init ();
71   serial_init_poll ();
72   console_init ();
73
74   /* Greet user. */
75   printf ("Pintos booting with %'zu kB RAM...\n", ram_pages * PGSIZE / 1024);
76
77   /* Parse command line. */
78   argv_init ();
79
80   /* Initialize memory system. */
81   paging_init ();
82   palloc_init ();
83   malloc_init ();
84
85   /* Segmentation. */
86 #ifdef USERPROG
87   tss_init ();
88   gdt_init ();
89 #endif
90
91   /* Set random seed if argv_init() didn't. */
92   random_init (0);
93
94   /* Initialize interrupt handlers. */
95   intr_init ();
96   timer_init ();
97   kbd_init ();
98 #ifdef USERPROG
99   exception_init ();
100   syscall_init ();
101 #endif
102
103   /* Start thread scheduler and enable interrupts. */
104   thread_start ();
105   serial_init_queue ();
106   timer_calibrate ();
107
108 #ifdef FILESYS
109   /* Initialize file system. */
110   disk_init ();
111   partition_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 (power_off_when_done) 
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
156 /* Populates the base page directory and page table with the
157    kernel virtual mapping, and then sets up the CPU to use the
158    new page directory.  Points base_page_dir to the page
159    directory it creates.
160
161    At the time this function is called, the active page table
162    (set up by start.S) only maps the first 4 MB of RAM, so we
163    should not try to access memory beyond that limit.
164    Fortunately, there is no need to do so. */
165 static void
166 paging_init (void)
167 {
168   uint32_t *pd, *pt;
169   size_t page;
170
171   pd = base_page_dir = ptov (LOADER_PD_BASE);
172   pt = ptov (LOADER_PT_BASE);
173   for (page = 0; page < ram_pages; page++) 
174     {
175       uintptr_t paddr = page * PGSIZE;
176       void *vaddr = ptov (paddr);
177       size_t pde_idx = pd_no (vaddr);
178       size_t pte_idx = pt_no (vaddr);
179
180       if (pd[pde_idx] == 0)
181         {
182           pt += PGSIZE / sizeof *pt;
183           memset (pt, 0, PGSIZE);
184           pd[pde_idx] = pde_create (pt);
185         }
186
187       pt[pte_idx] = pte_create_kernel (vaddr, true);
188     }
189
190   /* start.S mapped the beginning of physical memory to virtual
191      address 0.  We don't want that mapping anymore, so erase
192      it. */
193   pd[0] = 0;
194
195   /* Store the physical address of the page directory into CR3
196      aka PDBR (page directory base register).  This flushes the
197      TLB to make sure .  See [IA32-v2a] "MOV--Move
198      to/from Control Registers" and [IA32-v3] 3.7.5. */
199   asm volatile ("mov %%cr3, %0" :: "r" (vtop (base_page_dir)));
200 }
201
202 /* Parses the command line. */
203 static void
204 argv_init (void) 
205 {
206   char *cmd_line, *pos;
207   char *argv[LOADER_CMD_LINE_LEN / 2 + 2];
208   int argc = 0;
209   int i;
210
211   /* The command line is made up of null terminated strings
212      followed by an empty string.  Break it up into words. */
213   cmd_line = pos = ptov (LOADER_CMD_LINE);
214   printf ("Kernel command line:");
215   while (pos < cmd_line + LOADER_CMD_LINE_LEN)
216     {
217       ASSERT (argc < LOADER_CMD_LINE_LEN / 2);
218       if (*pos == '\0')
219         break;
220       argv[argc++] = pos;
221       printf (" %s", pos);
222       pos = strchr (pos, '\0') + 1;
223     }
224   printf ("\n");
225   argv[argc] = "";
226   argv[argc + 1] = "";
227
228   /* Parse the words. */
229   for (i = 0; i < argc; i++)
230     if (!strcmp (argv[i], "-rs")) 
231       random_init (atoi (argv[++i]));
232     else if (!strcmp (argv[i], "-d")) 
233       debug_enable (argv[++i]);
234     else if (!strcmp (argv[i], "-q"))
235       power_off_when_done = true;
236 #ifdef USERPROG
237     else if (!strcmp (argv[i], "-ex")) 
238       initial_program = argv[++i];
239     else if (!strcmp (argv[i], "-ul"))
240       user_page_limit = atoi (argv[++i]);
241 #endif
242 #ifdef FILESYS
243     else if (!strcmp (argv[i], "-f"))
244       format_filesys = true;
245     else if (!strcmp (argv[i], "-ci")) 
246       {
247         fsutil_copyin_file = argv[++i]; 
248         fsutil_copyin_size = atoi (argv[++i]); 
249       }
250     else if (!strcmp (argv[i], "-co"))
251       fsutil_copyout_file = argv[++i];
252     else if (!strcmp (argv[i], "-p")) 
253       fsutil_print_file = argv[++i];
254     else if (!strcmp (argv[i], "-r"))
255       fsutil_remove_file = argv[++i];
256     else if (!strcmp (argv[i], "-ls"))
257       fsutil_list_files = true;
258     else if (!strcmp (argv[i], "-D"))
259       fsutil_dump_filesys = true;
260 #endif
261     else if (!strcmp (argv[i], "-u"))
262       {
263         printf (
264           "Kernel options:\n"
265           " -rs SEED            Seed random seed to SEED.\n"
266           " -d CLASS[,...]      Enable the given classes of debug messages.\n"
267 #ifdef USERPROG
268           " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
269           " -ul USER_MAX        Limit user memory to USER_MAX pages.\n"
270 #endif
271 #ifdef FILESYS
272           " -f                  Format the file system disk (hdb or hd0:1).\n"
273           " -ci FILENAME SIZE   Copy SIZE bytes from the scratch disk (hdc\n"
274           "                     or hd1:0) into the file system as FILENAME\n"
275           " -co FILENAME        Copy FILENAME to the scratch disk, with\n"
276           "                     size at start of sector 0 and data afterward\n"
277           " -p FILENAME         Print the contents of FILENAME\n"
278           " -r FILENAME         Delete FILENAME\n"
279           " -ls                 List the files in the file system\n"
280           " -D                  Dump complete file system contents\n"
281 #endif
282           " -q                  Power off after doing requested actions.\n"
283           " -u                  Print this help message and power off.\n"
284           );
285         power_off ();
286       }
287     else 
288       PANIC ("unknown option `%s' (use -u for help)", argv[i]);
289 }
290
291 /* Powers down the machine we're running on,
292    as long as we're running on Bochs or qemu. */
293 void
294 power_off (void) 
295 {
296   const char s[] = "Shutdown";
297   const char *p;
298
299 #ifdef FILESYS
300   filesys_done ();
301 #endif
302
303   print_stats ();
304
305   printf ("Powering off...\n");
306   serial_flush ();
307
308   for (p = s; *p != '\0'; p++)
309     outb (0x8900, *p);
310   for (;;);
311 }
312
313 /* Print statistics about Pintos execution. */
314 static void
315 print_stats (void) 
316 {
317   timer_print_stats ();
318   thread_print_stats ();
319 #ifdef FILESYS
320   disk_print_stats ();
321 #endif
322   console_print_stats ();
323   kbd_print_stats ();
324 #ifdef USERPROG
325   exception_print_stats ();
326 #endif
327 }