Rewrite palloc code so that it only touches the first 4 MB of RAM.
[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   palloc_init ();
82   paging_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 = palloc_get_page (PAL_ASSERT | PAL_ZERO);
172   pt = NULL;
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 = palloc_get_page (PAL_ASSERT | PAL_ZERO);
183           pd[pde_idx] = pde_create (pt);
184         }
185
186       pt[pte_idx] = pte_create_kernel (vaddr, true);
187     }
188
189   /* Store the physical address of the page directory into CR3
190      aka PDBR (page directory base register).  This activates our
191      new page tables immediately.  See [IA32-v2a] "MOV--Move
192      to/from Control Registers" and [IA32-v3] 3.7.5. */
193   asm volatile ("mov %%cr3, %0" :: "r" (vtop (base_page_dir)));
194 }
195
196 /* Parses the command line. */
197 static void
198 argv_init (void) 
199 {
200   char *cmd_line, *pos;
201   char *argv[LOADER_CMD_LINE_LEN / 2 + 2];
202   int argc = 0;
203   int i;
204
205   /* The command line is made up of null terminated strings
206      followed by an empty string.  Break it up into words. */
207   cmd_line = pos = ptov (LOADER_CMD_LINE);
208   printf ("Kernel command line:");
209   while (pos < cmd_line + LOADER_CMD_LINE_LEN)
210     {
211       ASSERT (argc < LOADER_CMD_LINE_LEN / 2);
212       if (*pos == '\0')
213         break;
214       argv[argc++] = pos;
215       printf (" %s", pos);
216       pos = strchr (pos, '\0') + 1;
217     }
218   printf ("\n");
219   argv[argc] = "";
220   argv[argc + 1] = "";
221
222   /* Parse the words. */
223   for (i = 0; i < argc; i++)
224     if (!strcmp (argv[i], "-rs")) 
225       random_init (atoi (argv[++i]));
226     else if (!strcmp (argv[i], "-d")) 
227       debug_enable (argv[++i]);
228     else if (!strcmp (argv[i], "-q"))
229       power_off_when_done = true;
230 #ifdef USERPROG
231     else if (!strcmp (argv[i], "-ex")) 
232       initial_program = argv[++i];
233     else if (!strcmp (argv[i], "-ul"))
234       max_user_pages = atoi (argv[++i]);
235 #endif
236 #ifdef FILESYS
237     else if (!strcmp (argv[i], "-f"))
238       format_filesys = true;
239     else if (!strcmp (argv[i], "-ci")) 
240       {
241         fsutil_copyin_file = argv[++i]; 
242         fsutil_copyin_size = atoi (argv[++i]); 
243       }
244     else if (!strcmp (argv[i], "-co"))
245       fsutil_copyout_file = argv[++i];
246     else if (!strcmp (argv[i], "-p")) 
247       fsutil_print_file = argv[++i];
248     else if (!strcmp (argv[i], "-r"))
249       fsutil_remove_file = argv[++i];
250     else if (!strcmp (argv[i], "-ls"))
251       fsutil_list_files = true;
252     else if (!strcmp (argv[i], "-D"))
253       fsutil_dump_filesys = true;
254 #endif
255     else if (!strcmp (argv[i], "-u"))
256       {
257         printf (
258           "Kernel options:\n"
259           " -rs SEED            Seed random seed to SEED.\n"
260           " -d CLASS[,...]      Enable the given classes of debug messages.\n"
261 #ifdef USERPROG
262           " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
263           " -ul USER_MAX        Limit user memory to USER_MAX pages.\n"
264 #endif
265 #ifdef FILESYS
266           " -f                  Format the file system disk (hdb or hd0:1).\n"
267           " -ci FILENAME SIZE   Copy SIZE bytes from the scratch disk (hdc\n"
268           "                     or hd1:0) into the file system as FILENAME\n"
269           " -co FILENAME        Copy FILENAME to the scratch disk, with\n"
270           "                     size at start of sector 0 and data afterward\n"
271           " -p FILENAME         Print the contents of FILENAME\n"
272           " -r FILENAME         Delete FILENAME\n"
273           " -ls                 List the files in the file system\n"
274           " -D                  Dump complete file system contents\n"
275 #endif
276           " -q                  Power off after doing requested actions.\n"
277           " -u                  Print this help message and power off.\n"
278           );
279         power_off ();
280       }
281     else 
282       PANIC ("unknown option `%s' (use -u for help)", argv[i]);
283 }
284
285 /* Powers down the machine we're running on,
286    as long as we're running on Bochs or qemu. */
287 void
288 power_off (void) 
289 {
290   const char s[] = "Shutdown";
291   const char *p;
292
293 #ifdef FILESYS
294   filesys_done ();
295 #endif
296
297   print_stats ();
298
299   printf ("Powering off...\n");
300   serial_flush ();
301
302   for (p = s; *p != '\0'; p++)
303     outb (0x8900, *p);
304   for (;;);
305 }
306
307 /* Print statistics about Pintos execution. */
308 static void
309 print_stats (void) 
310 {
311   timer_print_stats ();
312   thread_print_stats ();
313 #ifdef FILESYS
314   disk_print_stats ();
315 #endif
316   console_print_stats ();
317   kbd_print_stats ();
318 #ifdef USERPROG
319   exception_print_stats ();
320 #endif
321 }