aboutsummaryrefslogtreecommitdiffstats
path: root/src/resume.c
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2011-07-10 22:35:07 -0400
committerKevin O'Connor <kevin@koconnor.net>2011-07-10 22:35:07 -0400
commit87b533bf71bb41e32319db0ed8f167f50171afc5 (patch)
tree5fc0cbb83ab7419a734393e4baaf09e05409970a /src/resume.c
parentffdcd3a8d72310efc55255fc93edf78c024bbafe (diff)
downloadseabios-87b533bf71bb41e32319db0ed8f167f50171afc5.tar.gz
Simplify POST entry code by moving reboot logic from post.c to resume.c.
Detect a resume/reboot by inspecting HaveRunPost instead of inspecting the cmos reset code. Inspecting a global variable is both simpler and safer. Move the reboot logic from post.c to resume.c - this makes the code in post.c simpler as it is now only called once on machine startup. This also makes it easier to ensure all POST initialization code resides in the relocatable "init" sections. Also, rename _start() to handle_post() so that it is more in keeping with the entry_xxx() and handle_xxx() function naming. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/resume.c')
-rw-r--r--src/resume.c111
1 files changed, 73 insertions, 38 deletions
diff --git a/src/resume.c b/src/resume.c
index 20e2e3dd..4390fb59 100644
--- a/src/resume.c
+++ b/src/resume.c
@@ -10,6 +10,12 @@
#include "biosvar.h" // struct bios_data_area_s
#include "bregs.h" // struct bregs
#include "acpi.h" // find_resume_vector
+#include "ps2port.h" // i8042_reboot
+#include "pci.h" // pci_reboot
+#include "cmos.h" // inb_cmos
+
+// Indicator if POST phase has been run.
+int HaveRunPost VAR16VISIBLE;
// Reset DMA controller
void
@@ -26,34 +32,19 @@ init_dma(void)
// Handler for post calls that look like a resume.
void VISIBLE16
-handle_resume(u8 status)
+handle_resume(void)
{
- init_dma();
-
debug_serial_setup();
+ int status = inb_cmos(CMOS_RESET_CODE);
+ outb_cmos(0, CMOS_RESET_CODE);
dprintf(1, "In resume (status=%d)\n", status);
+ init_dma();
+
switch (status) {
- case 0xfe:
- if (CONFIG_S3_RESUME) {
- // S3 resume request. Jump to 32bit mode to handle the resume.
- asm volatile(
- "movw %w1, %%ss\n"
- "movl %0, %%esp\n"
- "movl $_cfunc32flat_s3_resume, %%edx\n"
- "jmp transition32\n"
- : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0)
- );
- break;
- }
- // NO BREAK
- case 0x00:
- case 0x0d ... 0xfd:
- case 0xff:
- // Normal post - now that status has been cleared a reset will
- // run regular boot code..
- reset_vector();
- break;
+ case 0x01 ... 0x04:
+ case 0x06 ... 0x09:
+ panic("Unimplemented shutdown status: %02x\n", status);
case 0x05:
// flush keyboard (issue EOI) and jump via 40h:0067h
@@ -88,19 +79,33 @@ handle_resume(u8 status)
: : "m"(BDA_JUMP), "r"(SEG_BDA)
);
break;
+
+ default:
+ break;
}
- panic("Unimplemented shutdown status: %02x\n", status);
+ // Not a 16bit resume - do remaining checks in 32bit mode
+ asm volatile(
+ "movw %w1, %%ss\n"
+ "movl %0, %%esp\n"
+ "movl $_cfunc32flat_handle_resume32, %%edx\n"
+ "jmp transition32\n"
+ : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0), "a"(status)
+ );
}
-void VISIBLE32FLAT
+// Handle an S3 resume event
+static void
s3_resume(void)
{
- ASSERT32FLAT();
if (!CONFIG_S3_RESUME)
- panic("S3 resume support not compiled in.\n");
+ return;
- dprintf(1, "In 32bit resume\n");
+ u32 s3_resume_vector = find_resume_vector();
+ if (!s3_resume_vector) {
+ dprintf(1, "No resume vector set!\n");
+ return;
+ }
smm_init();
@@ -108,18 +113,48 @@ s3_resume(void)
make_bios_readonly();
- u32 s3_resume_vector = find_resume_vector();
-
// Invoke the resume vector.
struct bregs br;
memset(&br, 0, sizeof(br));
- if (s3_resume_vector) {
- dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
- br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
- } else {
- dprintf(1, "No resume vector set!\n");
- // Jump to the post vector to restart with a normal boot.
- br.code = SEGOFF(SEG_BIOS, (u32)reset_vector - BUILD_BIOS_ADDR);
- }
+ dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
+ br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
call16big(&br);
}
+
+// Attempt to invoke a hard-reboot.
+static void
+tryReboot(void)
+{
+ dprintf(1, "Attempting a hard reboot\n");
+
+ // Setup for reset on qemu.
+ if (! CONFIG_COREBOOT) {
+ qemu_prep_reset();
+ if (HaveRunPost)
+ apm_shutdown();
+ }
+
+ // Try keyboard controller reboot.
+ i8042_reboot();
+
+ // Try PCI 0xcf9 reboot
+ pci_reboot();
+
+ // Try triple fault
+ asm volatile("int3");
+
+ panic("Could not reboot");
+}
+
+void VISIBLE32FLAT
+handle_resume32(int status)
+{
+ ASSERT32FLAT();
+ dprintf(1, "In 32bit resume\n");
+
+ if (status == 0xfe)
+ s3_resume();
+
+ // Must be a soft reboot - invoke a hard reboot.
+ tryReboot();
+}