mask interrupts on S3 resume
[seabios.git] / src / resume.c
index 76a8c50d6a679d98077a56f2678dc37673ab0efa..f887f454e7cc8d351ade16669ca49d407616dfa9 100644 (file)
 #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
-init_dma()
+init_dma(void)
 {
     // first reset the DMA controllers
     outb(0, PORT_DMA1_MASTER_CLEAR);
@@ -26,46 +32,31 @@ init_dma()
 
 // 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"
-                "pushl $s3_resume\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
         eoi_pic2();
         // NO BREAK
     case 0x0a:
-#define BDA_JUMP_IP (((struct bios_data_area_s *)0)->jump_ip)
+#define BDA_JUMP (((struct bios_data_area_s *)0)->jump)
         // resume execution by jump via 40h:0067h
         asm volatile(
             "movw %w1, %%ds\n"
             "ljmpw *%0\n"
-            : : "m"(BDA_JUMP_IP), "r"(SEG_BDA)
+            : : "m"(BDA_JUMP), "r"(SEG_BDA)
             );
         break;
 
@@ -75,7 +66,7 @@ handle_resume(u8 status)
             "movw %w1, %%ds\n"
             "lssw %0, %%sp\n"
             "iretw\n"
-            : : "m"(BDA_JUMP_IP), "r"(SEG_BDA)
+            : : "m"(BDA_JUMP), "r"(SEG_BDA)
             );
         break;
 
@@ -85,42 +76,86 @@ handle_resume(u8 status)
             "movw %w1, %%ds\n"
             "lssw %0, %%sp\n"
             "lretw\n"
-            : : "m"(BDA_JUMP_IP), "r"(SEG_BDA)
+            : : "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)
+        );
 }
 
-#if MODE16==0
-void VISIBLE32
-s3_resume()
+// Handle an S3 resume event
+static void
+s3_resume(void)
 {
     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;
+    }
 
+    pic_setup();
     smm_init();
 
-    make_bios_readonly();
+    s3_resume_vga_init();
 
-    u32 s3_resume_vector = find_resume_vector();
+    make_bios_readonly();
 
     // 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.ip = FLATPTR_TO_OFFSET(s3_resume_vector);
-        br.cs = FLATPTR_TO_SEG(s3_resume_vector);
-    } else {
-        dprintf(1, "No resume vector set!\n");
-        // Jump to the post vector to restart with a normal boot.
-        br.ip = (u32)reset_vector - BUILD_BIOS_ADDR;
-        br.cs = SEG_BIOS;
-    }
+    dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
+    br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
     call16big(&br);
 }
-#endif
+
+// 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();
+}