132 lines
2.7 KiB
C
132 lines
2.7 KiB
C
|
#include "devices/shutdown.h"
|
||
|
#include <console.h>
|
||
|
#include <stdio.h>
|
||
|
#include "devices/kbd.h"
|
||
|
#include "devices/serial.h"
|
||
|
#include "devices/timer.h"
|
||
|
#include "threads/io.h"
|
||
|
#include "threads/thread.h"
|
||
|
#ifdef USERPROG
|
||
|
#include "userprog/exception.h"
|
||
|
#endif
|
||
|
#ifdef FILESYS
|
||
|
#include "devices/block.h"
|
||
|
#include "filesys/filesys.h"
|
||
|
#endif
|
||
|
|
||
|
/* Keyboard control register port. */
|
||
|
#define CONTROL_REG 0x64
|
||
|
|
||
|
/* How to shut down when shutdown() is called. */
|
||
|
static enum shutdown_type how = SHUTDOWN_NONE;
|
||
|
|
||
|
static void print_stats (void);
|
||
|
|
||
|
/* Shuts down the machine in the way configured by
|
||
|
shutdown_configure(). If the shutdown type is SHUTDOWN_NONE
|
||
|
(which is the default), returns without doing anything. */
|
||
|
void
|
||
|
shutdown (void)
|
||
|
{
|
||
|
switch (how)
|
||
|
{
|
||
|
case SHUTDOWN_POWER_OFF:
|
||
|
shutdown_power_off ();
|
||
|
break;
|
||
|
|
||
|
case SHUTDOWN_REBOOT:
|
||
|
shutdown_reboot ();
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
/* Nothing to do. */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Sets TYPE as the way that machine will shut down when Pintos
|
||
|
execution is complete. */
|
||
|
void
|
||
|
shutdown_configure (enum shutdown_type type)
|
||
|
{
|
||
|
how = type;
|
||
|
}
|
||
|
|
||
|
/* Reboots the machine via the keyboard controller. */
|
||
|
void
|
||
|
shutdown_reboot (void)
|
||
|
{
|
||
|
printf ("Rebooting...\n");
|
||
|
|
||
|
/* See [kbd] for details on how to program the keyboard
|
||
|
* controller. */
|
||
|
for (;;)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
/* Poll keyboard controller's status byte until
|
||
|
* 'input buffer empty' is reported. */
|
||
|
for (i = 0; i < 0x10000; i++)
|
||
|
{
|
||
|
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
|
||
|
shutdown_power_off (void)
|
||
|
{
|
||
|
const char s[] = "Shutdown";
|
||
|
const char *p;
|
||
|
|
||
|
#ifdef FILESYS
|
||
|
filesys_done ();
|
||
|
#endif
|
||
|
|
||
|
print_stats ();
|
||
|
|
||
|
printf ("Powering off...\n");
|
||
|
serial_flush ();
|
||
|
|
||
|
/* This is a special power-off sequence supported by Bochs and
|
||
|
QEMU, but not by physical hardware. */
|
||
|
for (p = s; *p != '\0'; p++)
|
||
|
outb (0x8900, *p);
|
||
|
|
||
|
/* This will power off a VMware VM if "gui.exitOnCLIHLT = TRUE"
|
||
|
is set in its configuration file. (The "pintos" script does
|
||
|
that automatically.) */
|
||
|
asm volatile ("cli; hlt" : : : "memory");
|
||
|
|
||
|
/* None of those worked. */
|
||
|
printf ("still running...\n");
|
||
|
for (;;);
|
||
|
}
|
||
|
|
||
|
/* Print statistics about Pintos execution. */
|
||
|
static void
|
||
|
print_stats (void)
|
||
|
{
|
||
|
timer_print_stats ();
|
||
|
thread_print_stats ();
|
||
|
#ifdef FILESYS
|
||
|
block_print_stats ();
|
||
|
#endif
|
||
|
console_print_stats ();
|
||
|
kbd_print_stats ();
|
||
|
#ifdef USERPROG
|
||
|
exception_print_stats ();
|
||
|
#endif
|
||
|
}
|