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