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