Implement a proper block layer with partition support.
[pintos-anon] / src / devices / shutdown.c
1 #include "devices/shutdown.h"
2 #include <console.h>
3 #include <stdio.h>
4 #include "devices/kbd.h"
5 #include "devices/serial.h"
6 #include "devices/timer.h"
7 #include "threads/io.h"
8 #include "threads/thread.h"
9 #ifdef USERPROG
10 #include "userprog/exception.h"
11 #endif
12 #ifdef FILESYS
13 #include "devices/block.h"
14 #include "filesys/filesys.h"
15 #endif
16
17 /* Keyboard control register port. */
18 #define CONTROL_REG 0x64
19
20 /* How to shut down when shutdown() is called. */
21 static enum shutdown_type how = SHUTDOWN_NONE;
22
23 static void print_stats (void);
24
25 /* Shuts down the machine in the way configured by
26    shutdown_configure().  If the shutdown type is SHUTDOWN_NONE
27    (which is the default), returns without doing anything. */
28 void
29 shutdown (void)
30 {
31   switch (how)
32     {
33     case SHUTDOWN_POWER_OFF:
34       shutdown_power_off ();
35       break;
36
37     case SHUTDOWN_REBOOT:
38       shutdown_reboot ();
39       break;
40
41     default:
42       /* Nothing to do. */
43       break;
44     }
45 }
46
47 /* Sets TYPE as the way that machine will shut down when Pintos
48    execution is complete. */
49 void
50 shutdown_configure (enum shutdown_type type)
51 {
52   how = type;
53 }
54
55 /* Reboots the machine via the keyboard controller. */
56 void
57 shutdown_reboot (void)
58 {
59   printf ("Rebooting...\n");
60
61     /* See [kbd] for details on how to program the keyboard
62      * controller. */
63   for (;;)
64     {
65       int i;
66
67       /* Poll keyboard controller's status byte until
68        * 'input buffer empty' is reported. */
69       for (i = 0; i < 0x10000; i++)
70         {
71           if ((inb (CONTROL_REG) & 0x02) == 0)
72             break;
73           timer_udelay (2);
74         }
75
76       timer_udelay (50);
77
78       /* Pulse bit 0 of the output port P2 of the keyboard controller.
79        * This will reset the CPU. */
80       outb (CONTROL_REG, 0xfe);
81       timer_udelay (50);
82     }
83 }
84
85 /* Powers down the machine we're running on,
86    as long as we're running on Bochs or QEMU. */
87 void
88 shutdown_power_off (void)
89 {
90   const char s[] = "Shutdown";
91   const char *p;
92
93 #ifdef FILESYS
94   filesys_done ();
95 #endif
96
97   print_stats ();
98
99   printf ("Powering off...\n");
100   serial_flush ();
101
102   /* This is a special power-off sequence supported by Bochs and
103      QEMU, but not by physical hardware. */
104   for (p = s; *p != '\0'; p++)
105     outb (0x8900, *p);
106
107   /* This will power off a VMware VM if "gui.exitOnCLIHLT = TRUE"
108      is set in its configuration file.  (The "pintos" script does
109      that automatically.)  */
110   asm volatile ("cli; hlt" : : : "memory");
111
112   /* None of those worked. */
113   printf ("still running...\n");
114   for (;;);
115 }
116
117 /* Print statistics about Pintos execution. */
118 static void
119 print_stats (void)
120 {
121   timer_print_stats ();
122   thread_print_stats ();
123 #ifdef FILESYS
124   block_print_stats ();
125 #endif
126   console_print_stats ();
127   kbd_print_stats ();
128 #ifdef USERPROG
129   exception_print_stats ();
130 #endif
131 }