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