Rename ram_pages to init_ram_pages.
[pintos-anon] / src / threads / init.c
index 8b2b7f76a4f89ba3d66be22e0a925e9682b4139a..d2d3e087de286cb8f5b48fd960d1568ae2d1cab4 100644 (file)
@@ -9,16 +9,18 @@
 #include <stdlib.h>
 #include <string.h>
 #include "devices/kbd.h"
 #include <stdlib.h>
 #include <string.h>
 #include "devices/kbd.h"
+#include "devices/input.h"
 #include "devices/serial.h"
 #include "devices/serial.h"
+#include "devices/shutdown.h"
 #include "devices/timer.h"
 #include "devices/vga.h"
 #include "devices/timer.h"
 #include "devices/vga.h"
+#include "devices/rtc.h"
 #include "threads/interrupt.h"
 #include "threads/io.h"
 #include "threads/loader.h"
 #include "threads/malloc.h"
 #include "threads/interrupt.h"
 #include "threads/io.h"
 #include "threads/loader.h"
 #include "threads/malloc.h"
-#include "threads/mmu.h"
 #include "threads/palloc.h"
 #include "threads/palloc.h"
-#include "threads/test.h"
+#include "threads/pte.h"
 #include "threads/thread.h"
 #ifdef USERPROG
 #include "userprog/process.h"
 #include "threads/thread.h"
 #ifdef USERPROG
 #include "userprog/process.h"
@@ -26,6 +28,8 @@
 #include "userprog/gdt.h"
 #include "userprog/syscall.h"
 #include "userprog/tss.h"
 #include "userprog/gdt.h"
 #include "userprog/syscall.h"
 #include "userprog/tss.h"
+#else
+#include "tests/threads/tests.h"
 #endif
 #ifdef FILESYS
 #include "devices/disk.h"
 #endif
 #ifdef FILESYS
 #include "devices/disk.h"
 #endif
 
 /* Amount of physical memory, in 4 kB pages. */
 #endif
 
 /* Amount of physical memory, in 4 kB pages. */
-size_t ram_pages;
+size_t init_ram_pages;
 
 /* Page directory with kernel mappings only. */
 
 /* Page directory with kernel mappings only. */
-uint32_t *base_page_dir;
+uint32_t *init_page_dir;
 
 #ifdef FILESYS
 
 #ifdef FILESYS
-/* -f: Format the filesystem? */
+/* -f: Format the file system? */
 static bool format_filesys;
 #endif
 
 static bool format_filesys;
 #endif
 
-#ifdef USERPROG
-/* -ex: Initial program to run. */
-static char *initial_program;
-#endif
-
-/* -q: Power off after kernel tasks complete? */
-bool power_off_when_done;
+/* -ul: Maximum number of pages to put into palloc's user pool. */
+static size_t user_page_limit = SIZE_MAX;
 
 static void ram_init (void);
 static void paging_init (void);
 
 static void ram_init (void);
 static void paging_init (void);
-static void argv_init (void);
-static void print_stats (void);
+
+static char **read_command_line (void);
+static char **parse_options (char **argv);
+static void run_actions (char **argv);
+static void usage (void);
 
 int main (void) NO_RETURN;
 
 
 int main (void) NO_RETURN;
 
+/* Pintos main program. */
 int
 main (void)
 {
 int
 main (void)
 {
+  char **argv;
+  
   /* Clear BSS and get machine's RAM size. */  
   ram_init ();
 
   /* Clear BSS and get machine's RAM size. */  
   ram_init ();
 
-  /* Initialize ourselves as a thread so we can use locks. */
-  thread_init ();
+  /* Break command line into arguments and parse options. */
+  argv = read_command_line ();
+  argv = parse_options (argv);
 
 
-  /* Initialize the console so we can use printf(). */
-  vga_init ();
-  serial_init_poll ();
-  console_init ();
+  /* Initialize ourselves as a thread so we can use locks,
+     then enable console locking. */
+  thread_init ();
+  console_init ();  
 
   /* Greet user. */
 
   /* Greet user. */
-  printf ("Pintos booting with %'zu kB RAM...\n", ram_pages * PGSIZE / 1024);
-
-  /* Parse command line. */
-  argv_init ();
+  printf ("Pintos booting with %'zu kB RAM...\n",
+          init_ram_pages * PGSIZE / 1024);
 
   /* Initialize memory system. */
 
   /* Initialize memory system. */
-  palloc_init ();
+  palloc_init (user_page_limit);
   malloc_init ();
   paging_init ();
 
   malloc_init ();
   paging_init ();
 
@@ -90,13 +94,11 @@ main (void)
   gdt_init ();
 #endif
 
   gdt_init ();
 #endif
 
-  /* Set random seed if argv_init() didn't. */
-  random_init (0);
-
   /* Initialize interrupt handlers. */
   intr_init ();
   timer_init ();
   kbd_init ();
   /* Initialize interrupt handlers. */
   intr_init ();
   timer_init ();
   kbd_init ();
+  input_init ();
 #ifdef USERPROG
   exception_init ();
   syscall_init ();
 #ifdef USERPROG
   exception_init ();
   syscall_init ();
@@ -108,31 +110,19 @@ main (void)
   timer_calibrate ();
 
 #ifdef FILESYS
   timer_calibrate ();
 
 #ifdef FILESYS
-  /* Initialize filesystem. */
+  /* Initialize file system. */
   disk_init ();
   filesys_init (format_filesys);
   disk_init ();
   filesys_init (format_filesys);
-  fsutil_run ();
 #endif
 
   printf ("Boot complete.\n");
   
 #endif
 
   printf ("Boot complete.\n");
   
-#ifdef USERPROG
-  /* Run a user program. */
-  if (initial_program != NULL)
-    {
-      printf ("\nExecuting '%s':\n", initial_program);
-      process_wait (process_execute (initial_program));
-    }
-#else
-  /* Run the compiled-in test function. */
-  test ();
-#endif
+  /* Run actions specified on kernel command line. */
+  run_actions (argv);
 
   /* Finish up. */
 
   /* Finish up. */
-  if (power_off_when_done) 
-    power_off ();
-  else 
-    thread_exit ();
+  shutdown ();
+  thread_exit ();
 }
 \f
 /* Clear BSS and obtain RAM size from loader. */
 }
 \f
 /* Clear BSS and obtain RAM size from loader. */
@@ -149,12 +139,12 @@ ram_init (void)
   memset (&_start_bss, 0, &_end_bss - &_start_bss);
 
   /* Get RAM size from loader.  See loader.S. */
   memset (&_start_bss, 0, &_end_bss - &_start_bss);
 
   /* Get RAM size from loader.  See loader.S. */
-  ram_pages = *(uint32_t *) ptov (LOADER_RAM_PAGES);
+  init_ram_pages = *(uint32_t *) ptov (LOADER_RAM_PGS);
 }
 
 /* Populates the base page directory and page table with the
    kernel virtual mapping, and then sets up the CPU to use the
 }
 
 /* Populates the base page directory and page table with the
    kernel virtual mapping, and then sets up the CPU to use the
-   new page directory.  Points base_page_dir to the page
+   new page directory.  Points init_page_dir to the page
    directory it creates.
 
    At the time this function is called, the active page table
    directory it creates.
 
    At the time this function is called, the active page table
@@ -166,15 +156,17 @@ paging_init (void)
 {
   uint32_t *pd, *pt;
   size_t page;
 {
   uint32_t *pd, *pt;
   size_t page;
+  extern char _start, _end_kernel_text;
 
 
-  pd = base_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
+  pd = init_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
   pt = NULL;
   pt = NULL;
-  for (page = 0; page < ram_pages; page++) 
+  for (page = 0; page < init_ram_pages; page++)
     {
       uintptr_t paddr = page * PGSIZE;
     {
       uintptr_t paddr = page * PGSIZE;
-      void *vaddr = ptov (paddr);
+      char *vaddr = ptov (paddr);
       size_t pde_idx = pd_no (vaddr);
       size_t pte_idx = pt_no (vaddr);
       size_t pde_idx = pd_no (vaddr);
       size_t pte_idx = pt_no (vaddr);
+      bool in_kernel_text = &_start <= vaddr && vaddr < &_end_kernel_text;
 
       if (pd[pde_idx] == 0)
         {
 
       if (pd[pde_idx] == 0)
         {
@@ -182,133 +174,196 @@ paging_init (void)
           pd[pde_idx] = pde_create (pt);
         }
 
           pd[pde_idx] = pde_create (pt);
         }
 
-      pt[pte_idx] = pte_create_kernel (vaddr, true);
+      pt[pte_idx] = pte_create_kernel (vaddr, !in_kernel_text);
     }
 
   /* Store the physical address of the page directory into CR3
      aka PDBR (page directory base register).  This activates our
      new page tables immediately.  See [IA32-v2a] "MOV--Move
     }
 
   /* Store the physical address of the page directory into CR3
      aka PDBR (page directory base register).  This activates our
      new page tables immediately.  See [IA32-v2a] "MOV--Move
-     to/from Control Registers" and [IA32-v3] 3.7.5. */
-  asm volatile ("mov %%cr3, %0" :: "r" (vtop (base_page_dir)));
+     to/from Control Registers" and [IA32-v3a] 3.7.5 "Base Address
+     of the Page Directory". */
+  asm volatile ("movl %0, %%cr3" : : "r" (vtop (init_page_dir)));
 }
 
 }
 
-/* Parses the command line. */
-static void
-argv_init (void) 
+/* Breaks the kernel command line into words and returns them as
+   an argv-like array. */
+static char **
+read_command_line (void) 
 {
 {
-  char *cmd_line, *pos;
-  char *argv[LOADER_CMD_LINE_LEN / 2 + 2];
-  int argc = 0;
+  static char *argv[LOADER_ARGS_LEN / 2 + 1];
+  char *p, *end;
+  int argc;
   int i;
 
   int i;
 
-  /* The command line is made up of null terminated strings
-     followed by an empty string.  Break it up into words. */
-  cmd_line = pos = ptov (LOADER_CMD_LINE);
-  printf ("Kernel command line:");
-  while (pos < cmd_line + LOADER_CMD_LINE_LEN)
+  argc = *(uint32_t *) ptov (LOADER_ARG_CNT);
+  p = ptov (LOADER_ARGS);
+  end = p + LOADER_ARGS_LEN;
+  for (i = 0; i < argc; i++) 
     {
     {
-      ASSERT (argc < LOADER_CMD_LINE_LEN / 2);
-      if (*pos == '\0')
-        break;
-      argv[argc++] = pos;
-      printf (" %s", pos);
-      pos = strchr (pos, '\0') + 1;
+      if (p >= end)
+        PANIC ("command line arguments overflow");
+
+      argv[i] = p;
+      p += strnlen (p, end - p) + 1;
     }
     }
-  printf ("\n");
-  argv[argc] = "";
-  argv[argc + 1] = "";
+  argv[argc] = NULL;
 
 
-  /* Parse the words. */
+  /* Print kernel command line. */
+  printf ("Kernel command line:");
   for (i = 0; i < argc; i++)
   for (i = 0; i < argc; i++)
-    if (!strcmp (argv[i], "-rs")) 
-      random_init (atoi (argv[++i]));
-    else if (!strcmp (argv[i], "-q"))
-      power_off_when_done = true;
-#ifdef USERPROG
-    else if (!strcmp (argv[i], "-ex")) 
-      initial_program = argv[++i];
-    else if (!strcmp (argv[i], "-ul"))
-      user_page_limit = atoi (argv[++i]);
-#endif
+    if (strchr (argv[i], ' ') == NULL)
+      printf (" %s", argv[i]);
+    else
+      printf (" '%s'", argv[i]);
+  printf ("\n");
+
+  return argv;
+}
+
+/* Parses options in ARGV[]
+   and returns the first non-option argument. */
+static char **
+parse_options (char **argv) 
+{
+  for (; *argv != NULL && **argv == '-'; argv++)
+    {
+      char *save_ptr;
+      char *name = strtok_r (*argv, "=", &save_ptr);
+      char *value = strtok_r (NULL, "", &save_ptr);
+      
+      if (!strcmp (name, "-h"))
+        usage ();
+      else if (!strcmp (name, "-q"))
+        shutdown_configure (SHUTDOWN_POWER_OFF);
+      else if (!strcmp (name, "-r"))
+        shutdown_configure (SHUTDOWN_REBOOT);
 #ifdef FILESYS
 #ifdef FILESYS
-    else if (!strcmp (argv[i], "-f"))
-      format_filesys = true;
-    else if (!strcmp (argv[i], "-ci")) 
-      {
-        fsutil_copyin_file = argv[++i]; 
-        fsutil_copyin_size = atoi (argv[++i]); 
-      }
-    else if (!strcmp (argv[i], "-co"))
-      fsutil_copyout_file = argv[++i];
-    else if (!strcmp (argv[i], "-p")) 
-      fsutil_print_file = argv[++i];
-    else if (!strcmp (argv[i], "-r"))
-      fsutil_remove_file = argv[++i];
-    else if (!strcmp (argv[i], "-ls"))
-      fsutil_list_files = true;
+      else if (!strcmp (name, "-f"))
+        format_filesys = true;
 #endif
 #endif
-    else if (!strcmp (argv[i], "-u"))
-      {
-        printf (
-          "Kernel options:\n"
-          " -rs SEED            Set random seed to SEED.\n"
+      else if (!strcmp (name, "-rs"))
+        random_init (atoi (value));
+      else if (!strcmp (name, "-mlfqs"))
+        thread_mlfqs = true;
 #ifdef USERPROG
 #ifdef USERPROG
-          " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
-          " -ul USER_MAX        Limit user memory to USER_MAX pages.\n"
+      else if (!strcmp (name, "-ul"))
+        user_page_limit = atoi (value);
 #endif
 #endif
-#ifdef FILESYS
-          " -f                  Format the filesystem disk (hdb or hd0:1).\n"
-          " -ci FILE SIZE       Copy SIZE bytes from the scratch disk (hdc\n"
-          "                     or hd1:0) into the filesystem as FILE.\n"
-          " -co FILE            Copy FILE to the scratch disk, with\n"
-          "                     size at start of sector 0 and data after.\n"
-          " -p FILE             Print the contents of FILE.\n"
-          " -r FILE             Delete FILE.\n"
-          " -ls                 List files in the root directory.\n"
+      else
+        PANIC ("unknown option `%s' (use -h for help)", name);
+    }
+
+  /* Initialize the random number generator based on the system
+     time.  This has no effect if an "-rs" option was specified.
+
+     When running under Bochs, this is not enough by itself to
+     get a good seed value, because the pintos script sets the
+     initial time to a predictable value, not to the local time,
+     for reproducibility.  To fix this, give the "-r" option to
+     the pintos script to request real-time execution. */
+  random_init (rtc_get_time ());
+  
+  return argv;
+}
+
+/* Runs the task specified in ARGV[1]. */
+static void
+run_task (char **argv)
+{
+  const char *task = argv[1];
+  
+  printf ("Executing '%s':\n", task);
+#ifdef USERPROG
+  process_wait (process_execute (task));
+#else
+  run_test (task);
 #endif
 #endif
-          " -q                  Power off after doing requested actions.\n"
-          " -u                  Print this help message and power off.\n"
-          );
-        power_off ();
-      }
-    else 
-      PANIC ("unknown option `%s' (use -u for help)", argv[i]);
+  printf ("Execution of '%s' complete.\n", task);
 }
 
 }
 
-/* Powers down the machine we're running on,
-   as long as we're running on Bochs or qemu. */
-void
-power_off (void
+/* Executes all of the actions specified in ARGV[]
+   up to the null pointer sentinel. */
+static void
+run_actions (char **argv
 {
 {
-  const char s[] = "Shutdown";
-  const char *p;
+  /* An action. */
+  struct action 
+    {
+      char *name;                       /* Action name. */
+      int argc;                         /* # of args, including action name. */
+      void (*function) (char **argv);   /* Function to execute action. */
+    };
 
 
+  /* Table of supported actions. */
+  static const struct action actions[] = 
+    {
+      {"run", 2, run_task},
 #ifdef FILESYS
 #ifdef FILESYS
-  filesys_done ();
+      {"ls", 1, fsutil_ls},
+      {"cat", 2, fsutil_cat},
+      {"rm", 2, fsutil_rm},
+      {"extract", 1, fsutil_extract},
+      {"append", 2, fsutil_append},
 #endif
 #endif
+      {NULL, 0, NULL},
+    };
 
 
-  print_stats ();
-
-  printf ("Powering off...\n");
-  serial_flush ();
-
-  for (p = s; *p != '\0'; p++)
-    outb (0x8900, *p);
-  for (;;);
+  while (*argv != NULL)
+    {
+      const struct action *a;
+      int i;
+
+      /* Find action name. */
+      for (a = actions; ; a++)
+        if (a->name == NULL)
+          PANIC ("unknown action `%s' (use -h for help)", *argv);
+        else if (!strcmp (*argv, a->name))
+          break;
+
+      /* Check for required arguments. */
+      for (i = 1; i < a->argc; i++)
+        if (argv[i] == NULL)
+          PANIC ("action `%s' requires %d argument(s)", *argv, a->argc - 1);
+
+      /* Invoke action and advance. */
+      a->function (argv);
+      argv += a->argc;
+    }
+  
 }
 
 }
 
-/* Print statistics about Pintos execution. */
+/* Prints a kernel command line help message and powers off the
+   machine. */
 static void
 static void
-print_stats (void) 
+usage (void)
 {
 {
-  timer_print_stats ();
-  thread_print_stats ();
+  printf ("\nCommand line syntax: [OPTION...] [ACTION...]\n"
+          "Options must precede actions.\n"
+          "Actions are executed in the order specified.\n"
+          "\nAvailable actions:\n"
+#ifdef USERPROG
+          "  run 'PROG [ARG...]' Run PROG and wait for it to complete.\n"
+#else
+          "  run TEST           Run TEST.\n"
+#endif
 #ifdef FILESYS
 #ifdef FILESYS
-  disk_print_stats ();
+          "  ls                 List files in the root directory.\n"
+          "  cat FILE           Print FILE to the console.\n"
+          "  rm FILE            Delete FILE.\n"
+          "Use these actions indirectly via `pintos' -g and -p options:\n"
+          "  extract            Untar from scratch disk into file system.\n"
+          "  append FILE        Append FILE to tar file on scratch disk.\n"
 #endif
 #endif
-  console_print_stats ();
-  kbd_print_stats ();
+          "\nOptions:\n"
+          "  -h                 Print this help message and power off.\n"
+          "  -q                 Power off VM after actions or on panic.\n"
+          "  -r                 Reboot after actions.\n"
+          "  -f                 Format file system disk during startup.\n"
+          "  -rs=SEED           Set random number seed to SEED.\n"
+          "  -mlfqs             Use multi-level feedback queue scheduler.\n"
 #ifdef USERPROG
 #ifdef USERPROG
-  exception_print_stats ();
+          "  -ul=COUNT          Limit user memory to COUNT pages.\n"
 #endif
 #endif
+          );
+  shutdown_power_off ();
 }
 }