1 #include "threads/init.h"
11 #include "devices/kbd.h"
12 #include "devices/input.h"
13 #include "devices/serial.h"
14 #include "devices/shutdown.h"
15 #include "devices/timer.h"
16 #include "devices/vga.h"
17 #include "devices/rtc.h"
18 #include "threads/interrupt.h"
19 #include "threads/io.h"
20 #include "threads/loader.h"
21 #include "threads/malloc.h"
22 #include "threads/palloc.h"
23 #include "threads/pte.h"
24 #include "threads/thread.h"
26 #include "userprog/process.h"
27 #include "userprog/exception.h"
28 #include "userprog/gdt.h"
29 #include "userprog/syscall.h"
30 #include "userprog/tss.h"
32 #include "tests/threads/tests.h"
35 #include "devices/block.h"
36 #include "devices/ide.h"
37 #include "filesys/filesys.h"
38 #include "filesys/fsutil.h"
41 /* Page directory with kernel mappings only. */
42 uint32_t *init_page_dir;
45 /* -f: Format the file system? */
46 static bool format_filesys;
48 /* -filesys, -scratch, -swap: Names of block devices to use,
49 overriding the defaults. */
50 static const char *filesys_bdev_name;
51 static const char *scratch_bdev_name;
53 static const char *swap_bdev_name;
57 /* -ul: Maximum number of pages to put into palloc's user pool. */
58 static size_t user_page_limit = SIZE_MAX;
60 static void bss_init (void);
61 static void paging_init (void);
63 static char **read_command_line (void);
64 static char **parse_options (char **argv);
65 static void run_actions (char **argv);
66 static void usage (void);
69 static void locate_block_devices (void);
70 static void locate_block_device (enum block_type, const char *name);
73 int main (void) NO_RETURN;
75 /* Pintos main program. */
84 /* Break command line into arguments and parse options. */
85 argv = read_command_line ();
86 argv = parse_options (argv);
88 /* Initialize ourselves as a thread so we can use locks,
89 then enable console locking. */
94 printf ("Pintos booting with %'"PRIu32" kB RAM...\n",
95 init_ram_pages * PGSIZE / 1024);
97 /* Initialize memory system. */
98 palloc_init (user_page_limit);
108 /* Initialize interrupt handlers. */
118 /* Start thread scheduler and enable interrupts. */
120 serial_init_queue ();
124 /* Initialize file system. */
126 locate_block_devices ();
127 filesys_init (format_filesys);
130 printf ("Boot complete.\n");
132 /* Run actions specified on kernel command line. */
140 /* Clear the "BSS", a segment that should be initialized to
141 zeros. It isn't actually stored on disk or zeroed by the
142 kernel loader, so we have to zero it ourselves.
144 The start and end of the BSS segment is recorded by the
145 linker as _start_bss and _end_bss. See kernel.lds. */
149 extern char _start_bss, _end_bss;
150 memset (&_start_bss, 0, &_end_bss - &_start_bss);
153 /* Populates the base page directory and page table with the
154 kernel virtual mapping, and then sets up the CPU to use the
155 new page directory. Points init_page_dir to the page
156 directory it creates. */
162 extern char _start, _end_kernel_text;
164 pd = init_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
166 for (page = 0; page < init_ram_pages; page++)
168 uintptr_t paddr = page * PGSIZE;
169 char *vaddr = ptov (paddr);
170 size_t pde_idx = pd_no (vaddr);
171 size_t pte_idx = pt_no (vaddr);
172 bool in_kernel_text = &_start <= vaddr && vaddr < &_end_kernel_text;
174 if (pd[pde_idx] == 0)
176 pt = palloc_get_page (PAL_ASSERT | PAL_ZERO);
177 pd[pde_idx] = pde_create (pt);
180 pt[pte_idx] = pte_create_kernel (vaddr, !in_kernel_text);
183 /* Store the physical address of the page directory into CR3
184 aka PDBR (page directory base register). This activates our
185 new page tables immediately. See [IA32-v2a] "MOV--Move
186 to/from Control Registers" and [IA32-v3a] 3.7.5 "Base Address
187 of the Page Directory". */
188 asm volatile ("movl %0, %%cr3" : : "r" (vtop (init_page_dir)));
191 /* Breaks the kernel command line into words and returns them as
192 an argv-like array. */
194 read_command_line (void)
196 static char *argv[LOADER_ARGS_LEN / 2 + 1];
201 argc = *(uint32_t *) ptov (LOADER_ARG_CNT);
202 p = ptov (LOADER_ARGS);
203 end = p + LOADER_ARGS_LEN;
204 for (i = 0; i < argc; i++)
207 PANIC ("command line arguments overflow");
210 p += strnlen (p, end - p) + 1;
214 /* Print kernel command line. */
215 printf ("Kernel command line:");
216 for (i = 0; i < argc; i++)
217 if (strchr (argv[i], ' ') == NULL)
218 printf (" %s", argv[i]);
220 printf (" '%s'", argv[i]);
226 /* Parses options in ARGV[]
227 and returns the first non-option argument. */
229 parse_options (char **argv)
231 for (; *argv != NULL && **argv == '-'; argv++)
234 char *name = strtok_r (*argv, "=", &save_ptr);
235 char *value = strtok_r (NULL, "", &save_ptr);
237 if (!strcmp (name, "-h"))
239 else if (!strcmp (name, "-q"))
240 shutdown_configure (SHUTDOWN_POWER_OFF);
241 else if (!strcmp (name, "-r"))
242 shutdown_configure (SHUTDOWN_REBOOT);
244 else if (!strcmp (name, "-f"))
245 format_filesys = true;
246 else if (!strcmp (name, "-filesys"))
247 filesys_bdev_name = value;
248 else if (!strcmp (name, "-scratch"))
249 scratch_bdev_name = value;
251 else if (!strcmp (name, "-swap"))
252 swap_bdev_name = value;
255 else if (!strcmp (name, "-rs"))
256 random_init (atoi (value));
257 else if (!strcmp (name, "-mlfqs"))
260 else if (!strcmp (name, "-ul"))
261 user_page_limit = atoi (value);
264 PANIC ("unknown option `%s' (use -h for help)", name);
267 /* Initialize the random number generator based on the system
268 time. This has no effect if an "-rs" option was specified.
270 When running under Bochs, this is not enough by itself to
271 get a good seed value, because the pintos script sets the
272 initial time to a predictable value, not to the local time,
273 for reproducibility. To fix this, give the "-r" option to
274 the pintos script to request real-time execution. */
275 random_init (rtc_get_time ());
280 /* Runs the task specified in ARGV[1]. */
282 run_task (char **argv)
284 const char *task = argv[1];
286 printf ("Executing '%s':\n", task);
288 process_wait (process_execute (task));
292 printf ("Execution of '%s' complete.\n", task);
295 /* Executes all of the actions specified in ARGV[]
296 up to the null pointer sentinel. */
298 run_actions (char **argv)
303 char *name; /* Action name. */
304 int argc; /* # of args, including action name. */
305 void (*function) (char **argv); /* Function to execute action. */
308 /* Table of supported actions. */
309 static const struct action actions[] =
311 {"run", 2, run_task},
313 {"ls", 1, fsutil_ls},
314 {"cat", 2, fsutil_cat},
315 {"rm", 2, fsutil_rm},
316 {"extract", 1, fsutil_extract},
317 {"append", 2, fsutil_append},
322 while (*argv != NULL)
324 const struct action *a;
327 /* Find action name. */
328 for (a = actions; ; a++)
330 PANIC ("unknown action `%s' (use -h for help)", *argv);
331 else if (!strcmp (*argv, a->name))
334 /* Check for required arguments. */
335 for (i = 1; i < a->argc; i++)
337 PANIC ("action `%s' requires %d argument(s)", *argv, a->argc - 1);
339 /* Invoke action and advance. */
346 /* Prints a kernel command line help message and powers off the
351 printf ("\nCommand line syntax: [OPTION...] [ACTION...]\n"
352 "Options must precede actions.\n"
353 "Actions are executed in the order specified.\n"
354 "\nAvailable actions:\n"
356 " run 'PROG [ARG...]' Run PROG and wait for it to complete.\n"
358 " run TEST Run TEST.\n"
361 " ls List files in the root directory.\n"
362 " cat FILE Print FILE to the console.\n"
363 " rm FILE Delete FILE.\n"
364 "Use these actions indirectly via `pintos' -g and -p options:\n"
365 " extract Untar from scratch device into file system.\n"
366 " append FILE Append FILE to tar file on scratch device.\n"
369 " -h Print this help message and power off.\n"
370 " -q Power off VM after actions or on panic.\n"
371 " -r Reboot after actions.\n"
373 " -f Format file system device during startup.\n"
374 " -filesys=BDEV Use BDEV for file system instead of default.\n"
375 " -scratch=BDEV Use BDEV for scratch instead of default.\n"
377 " -swap=BDEV Use BDEV for swap instead of default.\n"
380 " -rs=SEED Set random number seed to SEED.\n"
381 " -mlfqs Use multi-level feedback queue scheduler.\n"
383 " -ul=COUNT Limit user memory to COUNT pages.\n"
386 shutdown_power_off ();
390 /* Figure out what block devices to cast in the various Pintos roles. */
392 locate_block_devices (void)
394 locate_block_device (BLOCK_FILESYS, filesys_bdev_name);
395 locate_block_device (BLOCK_SCRATCH, scratch_bdev_name);
397 locate_block_device (BLOCK_SWAP, swap_bdev_name);
401 /* Figures out what block device to use for the given ROLE: the
402 block device with the given NAME, if NAME is non-null,
403 otherwise the first block device in probe order of type
406 locate_block_device (enum block_type role, const char *name)
408 struct block *block = NULL;
412 block = block_get_by_name (name);
414 PANIC ("No such block device \"%s\"", name);
418 for (block = block_first (); block != NULL; block = block_next (block))
419 if (block_type (block) == role)
425 printf ("%s: using %s\n", block_type_name (role), block_name (block));
426 block_set_role (role, block);