00001 #include "threads/init.h"
00002
00003 #include <console.h>
00004 #include <debug.h>
00005 #include <inttypes.h>
00006 #include <limits.h>
00007 #include <random.h>
00008 #include <stddef.h>
00009 #include <stdio.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012 #include "devices/kbd.h"
00013 #include "devices/input.h"
00014 #include "devices/pci.h"
00015 #include "devices/usb.h"
00016 #include "devices/serial.h"
00017 #include "devices/timer.h"
00018 #include "devices/vga.h"
00019 #include "devices/rtc.h"
00020 #include "threads/interrupt.h"
00021 #include "threads/io.h"
00022 #include "threads/loader.h"
00023 #include "threads/malloc.h"
00024 #include "threads/palloc.h"
00025 #include "threads/pte.h"
00026 #include "threads/thread.h"
00027 #ifdef USERPROG
00028 #include "userprog/process.h"
00029 #include "userprog/exception.h"
00030 #include "userprog/gdt.h"
00031 #include "userprog/syscall.h"
00032 #include "userprog/tss.h"
00033 #else
00034 #include "tests/threads/tests.h"
00035 #endif
00036 #ifdef FILESYS
00037 #include "devices/block.h"
00038 #include "devices/ide.h"
00039 #include "filesys/filesys.h"
00040 #include "filesys/fsutil.h"
00041 #endif
00042
00043
00044 uint32_t *base_page_dir;
00045 bool base_page_dir_initialized = 0;
00046
00047 #ifdef FILESYS
00048
00049 static bool format_filesys;
00050
00051
00052
00053 static const char *filesys_bdev_name;
00054 static const char *scratch_bdev_name;
00055 #ifdef VM
00056 static const char *swap_bdev_name;
00057 #endif
00058 #endif
00059
00060
00061 bool power_off_when_done;
00062
00063
00064 static bool reboot_when_done;
00065
00066 static void bss_init (void);
00067 static void paging_init (void);
00068 static void pci_zone_init (void);
00069
00070 static char **read_command_line (void);
00071 static char **parse_options (char **argv);
00072 static void run_actions (char **argv);
00073 static void usage (void);
00074
00075 #ifdef FILESYS
00076 static void locate_block_devices (void);
00077 static void locate_block_device (enum block_type, const char *name);
00078 #endif
00079
00080 static void print_stats (void);
00081
00082 int main (void) NO_RETURN;
00083
00084
00085 int
00086 main (void)
00087 {
00088 char **argv;
00089
00090
00091 bss_init ();
00092
00093
00094 argv = read_command_line ();
00095 argv = parse_options (argv);
00096
00097
00098
00099 thread_init ();
00100 console_init ();
00101
00102
00103 printf ("Pintos booting with %'"PRIu32" kB RAM...\n",
00104 ram_pages * PGSIZE / 1024);
00105
00106
00107 palloc_init ();
00108 malloc_init ();
00109 paging_init ();
00110
00111
00112 #ifdef USERPROG
00113 tss_init ();
00114 gdt_init ();
00115 #endif
00116
00117
00118 intr_init ();
00119 timer_init ();
00120 kbd_init ();
00121 pci_init ();
00122 input_init ();
00123 #ifdef USERPROG
00124 exception_init ();
00125 syscall_init ();
00126 #endif
00127
00128
00129 thread_start ();
00130 serial_init_queue ();
00131 timer_calibrate ();
00132 usb_init ();
00133
00134 #ifdef FILESYS
00135
00136 usb_storage_init ();
00137 ide_init ();
00138 locate_block_devices ();
00139 filesys_init (format_filesys);
00140 #endif
00141
00142 printf ("Boot complete.\n");
00143
00144
00145 run_actions (argv);
00146
00147
00148 if (reboot_when_done)
00149 reboot ();
00150
00151 if (power_off_when_done)
00152 power_off ();
00153 thread_exit ();
00154 }
00155
00156
00157
00158
00159
00160
00161
00162 static void
00163 bss_init (void)
00164 {
00165 extern char _start_bss, _end_bss;
00166 memset (&_start_bss, 0, &_end_bss - &_start_bss);
00167 }
00168
00169
00170
00171
00172
00173 static void
00174 paging_init (void)
00175 {
00176 uint32_t *pd, *pt;
00177 size_t page;
00178 extern char _start, _end_kernel_text;
00179
00180 pd = base_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
00181 pt = NULL;
00182 for (page = 0; page < ram_pages; page++)
00183 {
00184 uintptr_t paddr = page * PGSIZE;
00185 char *vaddr = ptov (paddr);
00186 size_t pde_idx = pd_no (vaddr);
00187 size_t pte_idx = pt_no (vaddr);
00188 bool in_kernel_text = &_start <= vaddr && vaddr < &_end_kernel_text;
00189
00190 if (pd[pde_idx] == 0)
00191 {
00192 pt = palloc_get_page (PAL_ASSERT | PAL_ZERO);
00193 pd[pde_idx] = pde_create_kernel (pt);
00194 }
00195
00196 pt[pte_idx] = pte_create_kernel (vaddr, !in_kernel_text);
00197 }
00198
00199 pci_zone_init ();
00200
00201
00202
00203
00204
00205
00206 asm volatile ("movl %0, %%cr3" : : "r" (vtop (base_page_dir)));
00207
00208 base_page_dir_initialized = 1;
00209 }
00210
00211
00212 static void
00213 pci_zone_init (void)
00214 {
00215 int i;
00216 for (i = 0; i < PCI_ADDR_ZONE_PDES; i++)
00217 {
00218 size_t pde_idx = pd_no ((void *) PCI_ADDR_ZONE_BEGIN) + i;
00219 uint32_t pde;
00220 void *pt;
00221
00222 pt = palloc_get_page (PAL_ASSERT | PAL_ZERO);
00223 pde = pde_create_kernel (pt);
00224 base_page_dir[pde_idx] = pde;
00225 }
00226 }
00227
00228
00229
00230 static char **
00231 read_command_line (void)
00232 {
00233 static char *argv[LOADER_ARGS_LEN / 2 + 1];
00234 char *p, *end;
00235 int argc;
00236 int i;
00237
00238 argc = *(uint32_t *) ptov (LOADER_ARG_CNT);
00239 p = ptov (LOADER_ARGS);
00240 end = p + LOADER_ARGS_LEN;
00241 for (i = 0; i < argc; i++)
00242 {
00243 if (p >= end)
00244 PANIC ("command line arguments overflow");
00245
00246 argv[i] = p;
00247 p += strnlen (p, end - p) + 1;
00248 }
00249 argv[argc] = NULL;
00250
00251
00252 printf ("Kernel command line:");
00253 for (i = 0; i < argc; i++)
00254 if (strchr (argv[i], ' ') == NULL)
00255 printf (" %s", argv[i]);
00256 else
00257 printf (" '%s'", argv[i]);
00258 printf ("\n");
00259
00260 return argv;
00261 }
00262
00263
00264
00265 static char **
00266 parse_options (char **argv)
00267 {
00268 for (; *argv != NULL && **argv == '-'; argv++)
00269 {
00270 char *save_ptr;
00271 char *name = strtok_r (*argv, "=", &save_ptr);
00272 char *value = strtok_r (NULL, "", &save_ptr);
00273
00274 if (!strcmp (name, "-h"))
00275 usage ();
00276 else if (!strcmp (name, "-q"))
00277 power_off_when_done = true;
00278 else if (!strcmp (name, "-r"))
00279 reboot_when_done = true;
00280 #ifdef FILESYS
00281 else if (!strcmp (name, "-f"))
00282 format_filesys = true;
00283 else if (!strcmp (name, "-filesys"))
00284 filesys_bdev_name = value;
00285 else if (!strcmp (name, "-scratch"))
00286 scratch_bdev_name = value;
00287 #ifdef VM
00288 else if (!strcmp (name, "-swap"))
00289 swap_bdev_name = value;
00290 #endif
00291 #endif
00292 else if (!strcmp (name, "-rs"))
00293 random_init (atoi (value));
00294 else if (!strcmp (name, "-mlfqs"))
00295 thread_mlfqs = true;
00296 #ifdef USERPROG
00297 else if (!strcmp (name, "-ul"))
00298 user_page_limit = atoi (value);
00299 #endif
00300 else
00301 PANIC ("unknown option `%s' (use -h for help)", name);
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 random_init (rtc_get_time ());
00313
00314 return argv;
00315 }
00316
00317
00318 static void
00319 run_task (char **argv)
00320 {
00321 const char *task = argv[1];
00322
00323 printf ("Executing '%s':\n", task);
00324 #ifdef USERPROG
00325 process_wait (process_execute (task));
00326 #else
00327 run_test (task);
00328 #endif
00329 printf ("Execution of '%s' complete.\n", task);
00330 }
00331
00332
00333
00334 static void
00335 run_actions (char **argv)
00336 {
00337
00338 struct action
00339 {
00340 char *name;
00341 int argc;
00342 void (*function) (char **argv);
00343 };
00344
00345
00346 static const struct action actions[] =
00347 {
00348 {"run", 2, run_task},
00349 #ifdef FILESYS
00350 {"ls", 1, fsutil_ls},
00351 {"cat", 2, fsutil_cat},
00352 {"rm", 2, fsutil_rm},
00353 {"extract", 1, fsutil_extract},
00354 {"append", 2, fsutil_append},
00355 #endif
00356 {NULL, 0, NULL},
00357 };
00358
00359 while (*argv != NULL)
00360 {
00361 const struct action *a;
00362 int i;
00363
00364
00365 for (a = actions; ; a++)
00366 if (a->name == NULL)
00367 PANIC ("unknown action `%s' (use -h for help)", *argv);
00368 else if (!strcmp (*argv, a->name))
00369 break;
00370
00371
00372 for (i = 1; i < a->argc; i++)
00373 if (argv[i] == NULL)
00374 PANIC ("action `%s' requires %d argument(s)", *argv, a->argc - 1);
00375
00376
00377 a->function (argv);
00378 argv += a->argc;
00379 }
00380
00381 }
00382
00383
00384
00385 static void
00386 usage (void)
00387 {
00388 printf ("\nCommand line syntax: [OPTION...] [ACTION...]\n"
00389 "Options must precede actions.\n"
00390 "Actions are executed in the order specified.\n"
00391 "\nAvailable actions:\n"
00392 #ifdef USERPROG
00393 " run 'PROG [ARG...]' Run PROG and wait for it to complete.\n"
00394 #else
00395 " run TEST Run TEST.\n"
00396 #endif
00397 #ifdef FILESYS
00398 " ls List files in the root directory.\n"
00399 " cat FILE Print FILE to the console.\n"
00400 " rm FILE Delete FILE.\n"
00401 "Use these actions indirectly via `pintos' -g and -p options:\n"
00402 " extract Untar from scratch disk into file system.\n"
00403 " append FILE Append FILE to tar file on scratch disk.\n"
00404 #endif
00405 "\nOptions:\n"
00406 " -h Print this help message and power off.\n"
00407 " -q Power off VM after actions or on panic.\n"
00408 " -r Reboot after actions.\n"
00409 #ifdef FILESYS
00410 " -f Format file system disk during startup.\n"
00411 " -filesys=BDEV Use BDEV for file system instead of default.\n"
00412 " -scratch=BDEV Use BDEV for scratch instead of default.\n"
00413 #ifdef VM
00414 " -swap=BDEV Use BDEV for swap instead of default.\n"
00415 #endif
00416 #endif
00417 " -rs=SEED Set random number seed to SEED.\n"
00418 " -mlfqs Use multi-level feedback queue scheduler.\n"
00419 #ifdef USERPROG
00420 " -ul=COUNT Limit user memory to COUNT pages.\n"
00421 #endif
00422 );
00423 power_off ();
00424 }
00425
00426 #ifdef FILESYS
00427
00428 static void
00429 locate_block_devices (void)
00430 {
00431 locate_block_device (BLOCK_FILESYS, filesys_bdev_name);
00432 locate_block_device (BLOCK_SCRATCH, scratch_bdev_name);
00433 #ifdef VM
00434 locate_block_device (BLOCK_SWAP, swap_bdev_name);
00435 #endif
00436 }
00437
00438
00439
00440
00441
00442 static void
00443 locate_block_device (enum block_type role, const char *name)
00444 {
00445 struct block *block = NULL;
00446
00447 if (name != NULL)
00448 {
00449 block = block_get_by_name (name);
00450 if (block == NULL)
00451 PANIC ("No such block device \"%s\"", name);
00452 }
00453 else
00454 {
00455 for (block = block_first (); block != NULL; block = block_next (block))
00456 if (block_type (block) == role)
00457 break;
00458 }
00459
00460 if (block != NULL)
00461 {
00462 printf ("%s: using %s\n", block_type_name (role), block_name (block));
00463 block_set_role (role, block);
00464 }
00465 }
00466 #endif
00467
00468
00469 #define CONTROL_REG 0x64
00470
00471
00472 void
00473 reboot (void)
00474 {
00475 int i;
00476
00477 printf ("Rebooting...\n");
00478
00479
00480
00481 for (i = 0; i < 100; i++)
00482 {
00483 int j;
00484
00485
00486
00487 for (j = 0; j < 0x10000; j++)
00488 {
00489 if ((inb (CONTROL_REG) & 0x02) == 0)
00490 break;
00491 timer_udelay (2);
00492 }
00493
00494 timer_udelay (50);
00495
00496
00497
00498 outb (CONTROL_REG, 0xfe);
00499 timer_udelay (50);
00500 }
00501 }
00502
00503
00504
00505 void
00506 power_off (void)
00507 {
00508 const char s[] = "Shutdown";
00509 const char *p;
00510
00511 #ifdef FILESYS
00512 filesys_done ();
00513 #endif
00514
00515 print_stats ();
00516
00517 printf ("Powering off...\n");
00518 serial_flush ();
00519
00520 for (p = s; *p != '\0'; p++)
00521 outb (0x8900, *p);
00522 asm volatile ("cli; hlt" : : : "memory");
00523 printf ("still running...\n");
00524 for (;;);
00525 }
00526
00527
00528 static void
00529 print_stats (void)
00530 {
00531 timer_print_stats ();
00532 thread_print_stats ();
00533 #ifdef FILESYS
00534 block_print_stats ();
00535 #endif
00536 console_print_stats ();
00537 kbd_print_stats ();
00538 #ifdef USERPROG
00539 exception_print_stats ();
00540 #endif
00541 }