Print statistics at power off.
[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 running requested actions? */
53 static bool do_power_off;
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   /* Initialize everything needed for printf() first. */
66   ram_init ();
67   thread_init ();
68   vga_init ();
69   serial_init_poll ();
70   console_init ();
71
72   /* Greet user. */
73   printf ("Pintos booting with %'zd kB RAM...\n", ram_pages * (PGSIZE / 1024));
74
75   /* Parse command line. */
76   argv_init ();
77
78   /* Initialize memory system, segments, paging. */
79   palloc_init ();
80   paging_init ();
81 #ifdef USERPROG
82   tss_init ();
83   gdt_init ();
84 #endif
85   malloc_init ();
86
87   /* Set random seed if argv_init() didn't. */
88   random_init (0);
89
90   /* Initialize interrupt handlers. */
91   intr_init ();
92   timer_init ();
93   kbd_init ();
94 #ifdef USERPROG
95   exception_init ();
96   syscall_init ();
97 #endif
98
99   /* Start thread scheduler and enable interrupts. */
100   thread_start ();
101   serial_init_queue ();
102
103 #ifdef FILESYS
104   /* Initialize filesystem. */
105   disk_init ();
106   filesys_init (format_filesys);
107   fsutil_run ();
108 #endif
109
110   printf ("Boot complete.\n");
111   
112 #ifdef USERPROG
113   /* Run a user program. */
114   if (initial_program != NULL)
115     {
116       tid_t tid;
117       printf ("\nExecuting '%s':\n", initial_program);
118       tid = process_execute (initial_program);
119 #ifdef THREAD_JOIN_IMPLEMENTED
120       if (tid != TID_ERROR)
121         thread_join (tid);
122 #endif
123     }
124 #else
125   test ();
126 #endif
127
128   if (do_power_off) 
129     power_off ();
130
131   /* Terminate this thread. */
132   thread_exit ();
133 }
134 \f
135 /* Clear BSS and obtain RAM size from loader. */
136 static void
137 ram_init (void) 
138 {
139   /* The "BSS" is a segment that should be initialized to zeros.
140      It isn't actually stored on disk or zeroed by the kernel
141      loader, so we have to zero it ourselves.
142
143      The start and end of the BSS segment is recorded by the
144      linker as _start_bss and _end_bss.  See kernel.lds. */
145   extern char _start_bss, _end_bss;
146   memset (&_start_bss, 0, &_end_bss - &_start_bss);
147
148   /* Get RAM size from loader.  See loader.S. */
149   ram_pages = *(uint32_t *) ptov (LOADER_RAM_PAGES);
150 }
151
152 /* Populates the base page directory and page table with the
153    kernel virtual mapping, and then sets up the CPU to use the
154    new page directory.  Points base_page_dir to the page
155    directory it creates.
156
157    At the time this function is called, the active page table
158    (set up by loader.S) only maps the first 4 MB of RAM, so we
159    should not try to use extravagant amounts of memory.
160    Fortunately, there is no need to do so. */
161 static void
162 paging_init (void)
163 {
164   uint32_t *pd, *pt;
165   size_t page;
166
167   pd = base_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
168   pt = NULL;
169   for (page = 0; page < ram_pages; page++) 
170     {
171       uintptr_t paddr = page * PGSIZE;
172       void *vaddr = ptov (paddr);
173       size_t pde_idx = pd_no (vaddr);
174       size_t pte_idx = pt_no (vaddr);
175
176       if (pd[pde_idx] == 0)
177         {
178           pt = palloc_get_page (PAL_ASSERT | PAL_ZERO);
179           pd[pde_idx] = pde_create (pt);
180         }
181
182       pt[pte_idx] = pte_create_kernel (vaddr, true);
183     }
184
185   asm volatile ("movl %0,%%cr3" :: "r" (vtop (base_page_dir)));
186 }
187
188 /* Parses the command line. */
189 static void
190 argv_init (void) 
191 {
192   char *cmd_line, *pos;
193   char *argv[LOADER_CMD_LINE_LEN / 2 + 2];
194   int argc = 0;
195   int i;
196
197   /* The command line is made up of null terminated strings
198      followed by an empty string.  Break it up into words. */
199   cmd_line = pos = ptov (LOADER_CMD_LINE);
200   printf ("Kernel command line:");
201   while (pos < cmd_line + LOADER_CMD_LINE_LEN)
202     {
203       ASSERT (argc < LOADER_CMD_LINE_LEN / 2);
204       if (*pos == '\0')
205         break;
206       argv[argc++] = pos;
207       printf (" %s", pos);
208       pos = strchr (pos, '\0') + 1;
209     }
210   printf ("\n");
211   argv[argc] = "";
212   argv[argc + 1] = "";
213
214   /* Parse the words. */
215   for (i = 0; i < argc; i++)
216     if (!strcmp (argv[i], "-rs")) 
217       random_init (atoi (argv[++i]));
218     else if (!strcmp (argv[i], "-d")) 
219       debug_enable (argv[++i]);
220     else if (!strcmp (argv[i], "-q"))
221       do_power_off = true;
222 #ifdef USERPROG
223     else if (!strcmp (argv[i], "-ex")) 
224       initial_program = argv[++i];
225 #endif
226 #ifdef FILESYS
227   else if (!strcmp (argv[i], "-f"))
228       format_filesys = true;
229     else if (!strcmp (argv[i], "-ci")) 
230       {
231         fsutil_copyin_file = argv[++i]; 
232         fsutil_copyin_size = atoi (argv[++i]); 
233       }
234     else if (!strcmp (argv[i], "-co"))
235       fsutil_copyout_file = argv[++i];
236     else if (!strcmp (argv[i], "-p")) 
237       fsutil_print_file = argv[++i];
238     else if (!strcmp (argv[i], "-r"))
239       fsutil_remove_file = argv[++i];
240     else if (!strcmp (argv[i], "-ls"))
241       fsutil_list_files = true;
242     else if (!strcmp (argv[i], "-D"))
243       fsutil_dump_filesys = true;
244 #endif
245     else if (!strcmp (argv[i], "-u"))
246       {
247         printf (
248           "Kernel options:\n"
249           " -rs SEED            Seed random seed to SEED.\n"
250           " -d CLASS[,...]      Enable the given classes of debug messages.\n"
251 #ifdef USERPROG
252           " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
253 #endif
254 #ifdef FILESYS
255           " -f                  Format the filesystem disk (hdb or hd0:1).\n"
256           " -ci FILENAME SIZE   Copy SIZE bytes from the scratch disk (hdc\n"
257           "                     or hd1:0) into the filesystem as FILENAME\n"
258           " -co FILENAME        Copy FILENAME to the scratch disk, with\n"
259           "                     size at start of sector 0 and data afterward\n"
260           " -p FILENAME         Print the contents of FILENAME\n"
261           " -r FILENAME         Delete FILENAME\n"
262           " -ls                 List the files in the filesystem\n"
263           " -D                  Dump complete filesystem contents\n"
264 #endif
265           " -q                  Power off after doing requested actions.\n"
266           " -u                  Print this help message and power off.\n"
267           );
268         power_off ();
269       }
270     else 
271       PANIC ("unknown option `%s' (use -u for help)", argv[i]);
272 }
273
274 /* Powers down the machine we're running on,
275    as long as we're running on Bochs or qemu. */
276 void
277 power_off (void) 
278 {
279   const char s[] = "Shutdown";
280   const char *p;
281
282 #ifdef FILESYS
283   filesys_done ();
284 #endif
285
286   print_stats ();
287
288   printf ("Powering off...\n");
289   serial_flush ();
290
291   for (p = s; *p != '\0'; p++)
292     outb (0x8900, *p);
293   for (;;);
294 }
295
296 /* Print statistics about Pintos execution. */
297 static void
298 print_stats (void) 
299 {
300   timer_print_stats ();
301   thread_print_stats ();
302 #ifdef FILESYS
303   disk_print_stats ();
304 #endif
305   console_print_stats ();
306   kbd_print_stats ();
307 #ifdef USERPROG
308   exception_print_stats ();
309 #endif
310 }