Add -ul option for limiting user pool size.
[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     else if (!strcmp (argv[i], "-ul"))
226       user_page_limit = atoi (argv[++i]);
227 #endif
228 #ifdef FILESYS
229     else if (!strcmp (argv[i], "-f"))
230       format_filesys = true;
231     else if (!strcmp (argv[i], "-ci")) 
232       {
233         fsutil_copyin_file = argv[++i]; 
234         fsutil_copyin_size = atoi (argv[++i]); 
235       }
236     else if (!strcmp (argv[i], "-co"))
237       fsutil_copyout_file = argv[++i];
238     else if (!strcmp (argv[i], "-p")) 
239       fsutil_print_file = argv[++i];
240     else if (!strcmp (argv[i], "-r"))
241       fsutil_remove_file = argv[++i];
242     else if (!strcmp (argv[i], "-ls"))
243       fsutil_list_files = true;
244     else if (!strcmp (argv[i], "-D"))
245       fsutil_dump_filesys = true;
246 #endif
247     else if (!strcmp (argv[i], "-u"))
248       {
249         printf (
250           "Kernel options:\n"
251           " -rs SEED            Seed random seed to SEED.\n"
252           " -d CLASS[,...]      Enable the given classes of debug messages.\n"
253 #ifdef USERPROG
254           " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
255           " -ul USER_MAX        Limit user memory to USER_MAX pages.\n"
256 #endif
257 #ifdef FILESYS
258           " -f                  Format the filesystem disk (hdb or hd0:1).\n"
259           " -ci FILENAME SIZE   Copy SIZE bytes from the scratch disk (hdc\n"
260           "                     or hd1:0) into the filesystem as FILENAME\n"
261           " -co FILENAME        Copy FILENAME to the scratch disk, with\n"
262           "                     size at start of sector 0 and data afterward\n"
263           " -p FILENAME         Print the contents of FILENAME\n"
264           " -r FILENAME         Delete FILENAME\n"
265           " -ls                 List the files in the filesystem\n"
266           " -D                  Dump complete filesystem contents\n"
267 #endif
268           " -q                  Power off after doing requested actions.\n"
269           " -u                  Print this help message and power off.\n"
270           );
271         power_off ();
272       }
273     else 
274       PANIC ("unknown option `%s' (use -u for help)", argv[i]);
275 }
276
277 /* Powers down the machine we're running on,
278    as long as we're running on Bochs or qemu. */
279 void
280 power_off (void) 
281 {
282   const char s[] = "Shutdown";
283   const char *p;
284
285 #ifdef FILESYS
286   filesys_done ();
287 #endif
288
289   print_stats ();
290
291   printf ("Powering off...\n");
292   serial_flush ();
293
294   for (p = s; *p != '\0'; p++)
295     outb (0x8900, *p);
296   for (;;);
297 }
298
299 /* Print statistics about Pintos execution. */
300 static void
301 print_stats (void) 
302 {
303   timer_print_stats ();
304   thread_print_stats ();
305 #ifdef FILESYS
306   disk_print_stats ();
307 #endif
308   console_print_stats ();
309   kbd_print_stats ();
310 #ifdef USERPROG
311   exception_print_stats ();
312 #endif
313 }