merged in all changes done to the trunk up to Aug 28
authorGodmar Back <godmar@gmail.com>
Thu, 28 Aug 2008 04:33:40 +0000 (04:33 +0000)
committerGodmar Back <godmar@gmail.com>
Thu, 28 Aug 2008 04:33:40 +0000 (04:33 +0000)
16 files changed:
src/devices/intq.c
src/devices/kbd.c
src/devices/timer.c
src/devices/timer.h
src/devices/usb.c
src/devices/usb.h
src/devices/usb_uhci.c
src/lib/debug.h
src/lib/kernel/debug.c
src/threads/init.c
src/threads/init.h
src/threads/interrupt.c
src/threads/palloc.c
src/threads/thread.c
src/threads/thread.h
src/utils/pintos

index 028dca4272aee56836c64a68974e8cd4bf4ef5a4..40b23ae6a48fe5bd0dfd3d1ed65b9ad97c31c505 100644 (file)
@@ -32,9 +32,8 @@ intq_full (const struct intq *q)
 }
 
 /* Removes a byte from Q and returns it.
-   Q must not be empty if called from an interrupt handler.
-   Otherwise, if Q is empty, first sleeps until a byte is
-   added. */
+   If Q is empty, sleeps until a byte is added.
+   When called from an interrupt handler, Q must not be empty. */
 uint8_t
 intq_getc (struct intq *q) 
 {
@@ -56,9 +55,8 @@ intq_getc (struct intq *q)
 }
 
 /* Adds BYTE to the end of Q.
-   Q must not be full if called from an interrupt handler.
-   Otherwise, if Q is full, first sleeps until a byte is
-   removed. */
+   If Q is full, sleeps until a byte is removed.
+   When called from an interrupt handler, Q must not be full. */
 void
 intq_putc (struct intq *q, uint8_t byte) 
 {
index 4d7dfdf1a315df6cd3b92564c2719bc815d694de..1aa71f5a3062c1888b3d3342d9a2d6675765b4e6 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <string.h>
 #include "devices/input.h"
+#include "threads/init.h"
 #include "threads/interrupt.h"
 #include "threads/io.h"
 
@@ -53,7 +54,7 @@ struct keymap
    that we handle elsewhere.  */
 static const struct keymap invariant_keymap[] = 
   {
-    {0x01, "\033"},
+    {0x01, "\033"},             /* Escape. */
     {0x0e, "\b"},
     {0x0f, "\tQWERTYUIOP"},
     {0x1c, "\r"},
@@ -61,6 +62,7 @@ static const struct keymap invariant_keymap[] =
     {0x2c, "ZXCVBNM"},
     {0x37, "*"},
     {0x39, " "},
+    {0x53, "\177"},             /* Delete. */
     {0, NULL},
   };
 
@@ -131,6 +133,10 @@ keyboard_interrupt (struct intr_frame *args UNUSED)
       /* Ordinary character. */
       if (!release) 
         {
+          /* Reboot if Ctrl+Alt+Del pressed. */
+          if (c == 0177 && ctrl && alt)
+            reboot ();
+
           /* Handle Ctrl, Shift.
              Note that Ctrl overrides Shift. */
           if (ctrl && c >= 0x40 && c < 0x60) 
index a83a588d6884dc271bca00909148c0348a0b986a..c97667f56bfcd5d9bd70862c7ff3ca2047f8f706 100644 (file)
@@ -28,6 +28,7 @@ static intr_handler_func timer_interrupt;
 static bool too_many_loops (unsigned loops);
 static void busy_wait (int64_t loops);
 static void real_time_sleep (int64_t num, int32_t denom);
+static void real_time_delay (int64_t num, int32_t denom);
 
 /* Sets up the timer to interrupt TIMER_FREQ times per second,
    and registers the corresponding interrupt. */
@@ -84,7 +85,8 @@ timer_elapsed (int64_t then)
   return timer_ticks () - then;
 }
 
-/* Suspends execution for approximately TICKS timer ticks. */
+/* Sleeps for approximately TICKS timer ticks.  Interrupts must
+   be turned on. */
 void
 timer_sleep (int64_t ticks) 
 {
@@ -95,27 +97,69 @@ timer_sleep (int64_t ticks)
     thread_yield ();
 }
 
-/* Suspends execution for approximately MS milliseconds. */
+/* Sleeps for approximately MS milliseconds.  Interrupts must be
+   turned on. */
 void
 timer_msleep (int64_t ms) 
 {
   real_time_sleep (ms, 1000);
 }
 
-/* Suspends execution for approximately US microseconds. */
+/* Sleeps for approximately US microseconds.  Interrupts must be
+   turned on. */
 void
 timer_usleep (int64_t us) 
 {
   real_time_sleep (us, 1000 * 1000);
 }
 
-/* Suspends execution for approximately NS nanoseconds. */
+/* Sleeps for approximately NS nanoseconds.  Interrupts must be
+   turned on. */
 void
 timer_nsleep (int64_t ns) 
 {
   real_time_sleep (ns, 1000 * 1000 * 1000);
 }
 
+/* Busy-waits for approximately MS milliseconds.  Interrupts need
+   not be turned on.
+
+   Busy waiting wastes CPU cycles, and busy waiting with
+   interrupts off for the interval between timer ticks or longer
+   will cause timer ticks to be lost.  Thus, use timer_msleep()
+   instead if interrupts are enabled. */
+void
+timer_mdelay (int64_t ms) 
+{
+  real_time_delay (ms, 1000);
+}
+
+/* Sleeps for approximately US microseconds.  Interrupts need not
+   be turned on.
+
+   Busy waiting wastes CPU cycles, and busy waiting with
+   interrupts off for the interval between timer ticks or longer
+   will cause timer ticks to be lost.  Thus, use timer_usleep()
+   instead if interrupts are enabled. */
+void
+timer_udelay (int64_t us) 
+{
+  real_time_delay (us, 1000 * 1000);
+}
+
+/* Sleeps execution for approximately NS nanoseconds.  Interrupts
+   need not be turned on.
+
+   Busy waiting wastes CPU cycles, and busy waiting with
+   interrupts off for the interval between timer ticks or longer
+   will cause timer ticks to be lost.  Thus, use timer_nsleep()
+   instead if interrupts are enabled.*/
+void
+timer_ndelay (int64_t ns) 
+{
+  real_time_delay (ns, 1000 * 1000 * 1000);
+}
+
 /* Prints timer statistics. */
 void
 timer_print_stats (void) 
@@ -187,10 +231,17 @@ real_time_sleep (int64_t num, int32_t denom)
   else 
     {
       /* Otherwise, use a busy-wait loop for more accurate
-         sub-tick timing.  We scale the numerator and denominator
-         down by 1000 to avoid the possibility of overflow. */
-      ASSERT (denom % 1000 == 0);
-      busy_wait (loops_per_tick * num / 1000 * TIMER_FREQ / (denom / 1000)); 
+         sub-tick timing. */
+      real_time_delay (num, denom); 
     }
 }
 
+/* Busy-wait for approximately NUM/DENOM seconds. */
+static void
+real_time_delay (int64_t num, int32_t denom)
+{
+  /* Scale the numerator and denominator down by 1000 to avoid
+     the possibility of overflow. */
+  ASSERT (denom % 1000 == 0);
+  busy_wait (loops_per_tick * num / 1000 * TIMER_FREQ / (denom / 1000)); 
+}
index 45a3f72e1127cd02f97b79d995277bec67a0812f..cd3d6bbfeb8d94046224d2676326705247f4a710 100644 (file)
@@ -13,11 +13,17 @@ void timer_calibrate (void);
 int64_t timer_ticks (void);
 int64_t timer_elapsed (int64_t);
 
+/* Sleep and yield the CPU to other threads. */
 void timer_sleep (int64_t ticks);
 void timer_msleep (int64_t milliseconds);
 void timer_usleep (int64_t microseconds);
 void timer_nsleep (int64_t nanoseconds);
 
+/* Busy waits. */
+void timer_mdelay (int64_t milliseconds);
+void timer_udelay (int64_t microseconds);
+void timer_ndelay (int64_t nanoseconds);
+
 void timer_print_stats (void);
 
 #endif /* devices/timer.h */
index b885eb1442ccf8f14576f154e7b47aa61c10a3d6..1ac802f563496e769945024c24b70a5b55409e55 100644 (file)
@@ -260,7 +260,8 @@ usb_configure_default (struct host *h)
   host_dev_info hi;
   host_eop_info cfg_eop;
   bool ignore_device = false;
-  int err, sz, txed;
+  int err, sz; 
+  unsigned txed;
   int config_val;
 
   hi = h->dev->create_dev_channel (h->info, ADDR_DEFAULT, USB_VERSION_1_1);
@@ -431,7 +432,7 @@ usb_load_config (struct usb_dev *dev, int idx, void *data, int dsz)
 
   sz = usb_tx_all (&dev->cfg_eop, cd, dsz,
                   sizeof (struct config_descriptor), true);
-  if (sz < sizeof (struct config_descriptor))
+  if (sz < (int) sizeof (struct config_descriptor))
     {
       printf ("USB: Did not rx GET descriptor (%d bytes, expected %d)\n", sz,
              sizeof (struct config_descriptor));
index 4ecce3b5ec225590b6f4a79b4d4138103aff47a8..f82762f5c231b84335b3b7ed77541f650720bd45 100644 (file)
@@ -185,6 +185,7 @@ struct usb_setup_pkt
 #pragma pack()
 
 void usb_init (void);
+void usb_storage_init (void);
 
 void usb_register_host (struct usb_host *, host_info info);
 int usb_unregister_host (struct usb_host *, host_info info);
index 77b8333ab80f3427d1d20307133fdc86222ccfe9..9cd4d694c564fc28d3e2ac83ac007fe31ce117b3 100644 (file)
@@ -225,7 +225,7 @@ static void qh_free (struct uhci_info *ui, struct queue_head *qh);
 static struct queue_head *qh_alloc (struct uhci_info *ui);
 
 static struct uhci_info *uhci_create_info (struct pci_io *io);
-static void uhci_destroy_info (struct uhci_info *ui);
+static void uhci_destroy_info (struct uhci_info *ui) UNUSED;
 static host_eop_info uhci_create_eop (host_dev_info hd, int eop, int maxpkt);
 static void uhci_remove_eop (host_eop_info hei);
 static host_dev_info uhci_create_chan (host_info hi, int dev_addr, int ver);
@@ -253,7 +253,7 @@ static void uhci_irq (void *uhci_data);
 static void uhci_detect_ports (struct uhci_info *ui);
 
 static int uhci_remove_stalled (struct uhci_info *ui);
-static void uhci_stall_watchdog (struct uhci_info *ui);
+static void uhci_stall_watchdog (struct uhci_info *ui) UNUSED;
 
 static void dump_all_qh (struct uhci_info *ui);
 static void dump_qh (struct queue_head *qh);
@@ -262,7 +262,6 @@ static void dump_regs (struct uhci_info *ui);
 
 void uhci_init (void);
 
-
 static struct usb_host uhci_host = {
   .name = "UHCI",
   .tx_pkt = uhci_tx_pkt,
@@ -433,7 +432,6 @@ dump_regs (struct uhci_info *ui)
     }
 }
 
-
 static void
 uhci_destroy_info (struct uhci_info *ui)
 {
@@ -586,7 +584,7 @@ token_to_pid (int token)
 
 static void
 uhci_setup_td (struct tx_descriptor *td, int dev_addr, int token,
-              int eop, void *pkt, int sz, int toggle, bool ls)
+              int eop, void *pkt, int sz, int toggle, bool ls UNUSED)
 {
   td->buf_ptr = (sz == 0) ? 0 : vtop (pkt);
 
@@ -643,7 +641,6 @@ uhci_tx_pkt_wait (struct uhci_eop_info *ue, int token, void *pkt,
   struct usb_wait w;
   int err;
   struct uhci_dev_info *ud;
-  int n;
 
   ud = ue->ud;
 
index 3218ab61360d8753c113674005dd8890d584aa95..888ab7b9d985d96033f9ee3c00a2876476256a7c 100644 (file)
@@ -16,6 +16,7 @@
 void debug_panic (const char *file, int line, const char *function,
                   const char *message, ...) PRINTF_FORMAT (4, 5) NO_RETURN;
 void debug_backtrace (void);
+void debug_backtrace_all (void);
 
 #endif
 
index 93c395208068801dcdbca3b4dffbec7b64c74712..22801954dd66512d489287a629371c6d88133ecf 100644 (file)
@@ -7,6 +7,9 @@
 #include <string.h>
 #include "threads/init.h"
 #include "threads/interrupt.h"
+#include "threads/thread.h"
+#include "threads/switch.h"
+#include "threads/vaddr.h"
 #include "devices/serial.h"
 
 /* Halts the OS, printing the source file name, line number, and
@@ -46,3 +49,75 @@ debug_panic (const char *file, int line, const char *function,
     power_off ();
   for (;;);
 }
+
+/* Print call stack of a thread.
+   The thread may be running, ready, or blocked. */
+static void
+print_stacktrace(struct thread *t, void *aux UNUSED)
+{
+  void *retaddr = NULL, **frame = NULL;
+  const char *status = "UNKNOWN";
+
+  switch (t->status) {
+    case THREAD_RUNNING:  
+      status = "RUNNING";
+      break;
+
+    case THREAD_READY:  
+      status = "READY";
+      break;
+
+    case THREAD_BLOCKED:  
+      status = "BLOCKED";
+      break;
+
+    default:
+      break;
+  }
+
+  printf ("Call stack of thread `%s' (status %s):", t->name, status);
+
+  if (t == thread_current()) 
+    {
+      frame = __builtin_frame_address (1);
+      retaddr = __builtin_return_address (0);
+    }
+  else
+    {
+      /* Retrieve the values of the base and instruction pointers
+         as they were saved when this thread called switch_threads. */
+      struct switch_threads_frame * saved_frame;
+
+      saved_frame = (struct switch_threads_frame *)t->stack;
+
+      /* Skip threads if they have been added to the all threads
+         list, but have never been scheduled.
+         We can identify because their `stack' member either points 
+         at the top of their kernel stack page, or the 
+         switch_threads_frame's 'eip' member points at switch_entry.
+         See also threads.c. */
+      if (t->stack == (uint8_t *)t + PGSIZE || saved_frame->eip == switch_entry)
+        {
+          printf (" thread was never scheduled.\n");
+          return;
+        }
+
+      frame = (void **) saved_frame->ebp;
+      retaddr = (void *) saved_frame->eip;
+    }
+
+  printf (" %p", retaddr);
+  for (; (uintptr_t) frame >= 0x1000 && frame[0] != NULL; frame = frame[0])
+    printf (" %p", frame[1]);
+  printf (".\n");
+}
+
+/* Prints call stack of all threads. */
+void
+debug_backtrace_all (void)
+{
+  enum intr_level oldlevel = intr_disable ();
+
+  thread_foreach (print_stacktrace, 0);
+  intr_set_level (oldlevel);
+}
index 66bc8671ee0b95810199247057a4cd407ee6f1e7..c60f79ea22be7b26677bc84ce573881dccc792fd 100644 (file)
@@ -59,6 +59,9 @@ static const char *swap_bdev_name;
 /* -q: Power off after kernel tasks complete? */
 bool power_off_when_done;
 
+/* -r: Reboot after kernel tasks complete? */
+static bool reboot_when_done;
+
 static void bss_init (void);
 static void paging_init (void);
 static void pci_zone_init (void);
@@ -141,6 +144,9 @@ main (void)
   run_actions (argv);
 
   /* Finish up. */
+  if (reboot_when_done)
+    reboot ();
   if (power_off_when_done)
     power_off ();
   thread_exit ();
@@ -268,6 +274,8 @@ parse_options (char **argv)
         usage ();
       else if (!strcmp (name, "-q"))
         power_off_when_done = true;
+      else if (!strcmp (name, "-r"))
+        reboot_when_done = true;
 #ifdef FILESYS
       else if (!strcmp (name, "-f"))
         format_filesys = true;
@@ -391,11 +399,12 @@ usage (void)
           "  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"
-          "  get FILE           Get FILE from file system into scratch disk.\n"
+          "  append FILE        Append FILE to tar file on scratch disk.\n"
 #endif
           "\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"
 #ifdef FILESYS
           "  -f                 Format file system disk during startup.\n"
           "  -filesys=BDEV      Use BDEV for file system instead of default.\n"
@@ -455,6 +464,41 @@ locate_block_device (enum block_type role, const char *name)
 }
 #endif
 
+/* Keyboard control register port. */
+#define CONTROL_REG 0x64
+
+/* Reboots the machine via the keyboard controller. */
+void
+reboot (void)
+{
+  int i;
+
+  printf ("Rebooting...\n");
+
+    /* See [kbd] for details on how to program the keyboard
+     * controller. */
+  for (i = 0; i < 100; i++) 
+    {
+      int j;
+
+      /* Poll keyboard controller's status byte until 
+       * 'input buffer empty' is reported. */
+      for (j = 0; j < 0x10000; j++) 
+        {
+          if ((inb (CONTROL_REG) & 0x02) == 0)   
+            break;
+          timer_udelay (2);
+        }
+
+      timer_udelay (50);
+
+      /* Pulse bit 0 of the output port P2 of the keyboard controller. 
+       * This will reset the CPU. */
+      outb (CONTROL_REG, 0xfe);
+      timer_udelay (50);
+    }
+}
+
 /* Powers down the machine we're running on,
    as long as we're running on Bochs or QEMU. */
 void
index 863d1de6df079ea8e7567e49d3d3298ec7c8ade3..36b41877d24fc1c9ac133b217e826b677a851c22 100644 (file)
@@ -13,5 +13,6 @@ extern uint32_t *base_page_dir;
 extern bool power_off_when_done;
 
 void power_off (void) NO_RETURN;
+void reboot (void);
 
 #endif /* threads/init.h */
index 27f470861a22de11b725475b731d2a11afdfafcc..24539e6ccc11a2839abd88319deee2208c015049 100644 (file)
 #define IRQ_CASCADE0   2
 #define IRQ_CASCADE1   9
 
+/* Programmable Interrupt Controller (PIC) registers.
+   A PC has two PICs, called the master and slave PICs, with the
+   slave attached ("cascaded") to the master IRQ line 2. */
+#define PIC0_CTRL      0x20    /* Master PIC control register address. */
+#define PIC0_DATA      0x21    /* Master PIC data register address. */
+#define PIC1_CTRL      0xa0    /* Slave PIC control register address. */
+#define PIC1_DATA      0xa1    /* Slave PIC data register address. */
+
 /* Number of x86 interrupts. */
 #define INTR_CNT 256
 
index ddbfeda1cdecaa511b775aa3f7ccd9f5ea043c99..46bfefcafa029e5478a5049bbba7bd869d93a434 100644 (file)
@@ -42,7 +42,6 @@ size_t user_page_limit = SIZE_MAX;
 static void init_pool (struct pool *, void *base, size_t page_cnt,
                        const char *name);
 static bool page_from_pool (const struct pool *, void *page);
-static void page_set_cache(void* page, bool enable_cache);
 
 /* Initializes the page allocator. */
 void
index 92d1aa899efe1d8bf84c6c7056ae7d45215c687b..2532463bdbbf5d8f2544cba0b590ae070d2d07e1 100644 (file)
    that are ready to run but not actually running. */
 static struct list ready_list;
 
+/* List of all processes.  Processes are added to this list
+   when they are first scheduled and removed when they exit. */
+static struct list all_list;
+
 /* Idle thread. */
 static struct thread *idle_thread;
 
@@ -87,6 +91,7 @@ thread_init (void)
 
   lock_init (&tid_lock);
   list_init (&ready_list);
+  list_init (&all_list);
 
   /* Set up a thread structure for the running thread. */
   initial_thread = running_thread ();
@@ -166,6 +171,7 @@ thread_create (const char *name, int priority,
   struct switch_entry_frame *ef;
   struct switch_threads_frame *sf;
   tid_t tid;
+  enum intr_level old_level;
 
   ASSERT (function != NULL);
 
@@ -178,6 +184,11 @@ thread_create (const char *name, int priority,
   init_thread (t, name, priority);
   tid = t->tid = allocate_tid ();
 
+  /* Prepare thread for first run by initializing its stack.
+     Do this atomically so intermediate values for the 'stack' 
+     member cannot be observed. */
+  old_level = intr_disable ();
+
   /* Stack frame for kernel_thread(). */
   kf = alloc_frame (t, sizeof *kf);
   kf->eip = NULL;
@@ -191,6 +202,9 @@ thread_create (const char *name, int priority,
   /* Stack frame for switch_threads(). */
   sf = alloc_frame (t, sizeof *sf);
   sf->eip = switch_entry;
+  sf->ebp = 0;
+
+  intr_set_level (old_level);
 
   /* Add to run queue. */
   thread_unblock (t);
@@ -280,9 +294,11 @@ thread_exit (void)
   process_exit ();
 #endif
 
-  /* Just set our status to dying and schedule another process.
-     We will be destroyed during the call to schedule_tail(). */
+  /* Remove thread from all threads list, set our status to dying,
+     and schedule another process.  That process will destroy us
+     when it call schedule_tail(). */
   intr_disable ();
+  list_remove (&thread_current()->allelem);
   thread_current ()->status = THREAD_DYING;
   schedule ();
   NOT_REACHED ();
@@ -306,6 +322,23 @@ thread_yield (void)
   intr_set_level (old_level);
 }
 
+/* Invoke function 'func' on all threads, passing along 'aux'.
+   This function must be called with interrupts off. */
+void
+thread_foreach (thread_action_func *func, void *aux)
+{
+  struct list_elem *e;
+
+  ASSERT (intr_get_level () == INTR_OFF);
+
+  for (e = list_begin (&all_list); e != list_end (&all_list);
+       e = list_next (e))
+    {
+      struct thread *t = list_entry (e, struct thread, allelem);
+      func (t, aux);
+    }
+}
+
 /* Sets the current thread's priority to NEW_PRIORITY. */
 void
 thread_set_priority (int new_priority) 
@@ -436,6 +469,7 @@ init_thread (struct thread *t, const char *name, int priority)
   t->stack = (uint8_t *) t + PGSIZE;
   t->priority = priority;
   t->magic = THREAD_MAGIC;
+  list_push_back (&all_list, &t->allelem);
 }
 
 /* Allocates a SIZE-byte frame at the top of thread T's stack and
index 0039560018ddc942fb2f10002ddd4d94e3045b8c..7965c0607815eab3275da7babdf669177f18c8e2 100644 (file)
@@ -88,6 +88,7 @@ struct thread
     char name[16];                      /* Name (for debugging purposes). */
     uint8_t *stack;                     /* Saved stack pointer. */
     int priority;                       /* Priority. */
+    struct list_elem allelem;           /* List element for all threads list. */
 
     /* Shared between thread.c and synch.c. */
     struct list_elem elem;              /* List element. */
@@ -125,6 +126,10 @@ const char *thread_name (void);
 void thread_exit (void) NO_RETURN;
 void thread_yield (void);
 
+/* Performs some operation on thread t, given auxiliary data AUX. */
+typedef void thread_action_func (struct thread *t, void *aux);
+void thread_foreach (thread_action_func *, void *);
+
 int thread_get_priority (void);
 void thread_set_priority (int);
 
index a62b1923bd9008f4d3c611a0a2fbb6546105e22a..d42669c7a198cae14c261b58c18245afd3024ebf 100755 (executable)
@@ -585,8 +585,11 @@ panic: action=fatal
 user_shortcut: keys=ctrlaltdel
 EOF
     print BOCHSRC "gdbstub: enabled=1\n" if $debug eq 'gdb';
-    print BOCHSRC "clock: sync=", $realtime ? 'realtime' : 'none',
-      ", time0=0\n";
+    if ($realtime) {
+       print BOCHSRC "clock: sync=realtime\n";
+    } else {
+       print BOCHSRC "clock: sync=none, time0=0\n";
+    }
     print BOCHSRC "ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15\n"
       if @disks > 2;
     print_bochs_disk_line ("ata0-master", $disks[0]);