mask interrupts on S3 resume
[seabios.git] / src / resume.c
index 4ff313386eb911e8e4e3577315d3d186f0dcc2da..f887f454e7cc8d351ade16669ca49d407616dfa9 100644 (file)
@@ -1,8 +1,8 @@
 // Code for handling calls to "post" that are resume related.
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 //
-// This file may be distributed under the terms of the GNU GPLv3 license.
+// This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "util.h" // dprintf
 #include "ioport.h" // outb
 #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,101 +32,130 @@ 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);
 
-    switch (status) {
-    case 0xfe:
-        // S3 resume request.  Jump to 32bit mode to handle the resume.
-        asm volatile(
-            "movw %%ax, %%ss\n"
-            "movl %0, %%esp\n"
-            "pushl $_code32_s3_resume\n"
-            "jmp transition32\n"
-            : : "i"(BUILD_S3RESUME_STACK_ADDR), "a"(0)
-            );
-        break;
+    init_dma();
 
-    case 0x00:
-    case 0x09:
-    case 0x0d ... 0xfd:
-    case 0xff:
-        // Normal post - now that status has been cleared a reset will
-        // run regular boot code..
-        reset_vector();
-        break;
+    switch (status) {
+    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 (((struct bios_data_area_s *)0)->jump)
         // resume execution by jump via 40h:0067h
-#define bda ((struct bios_data_area_s *)MAKE_FARPTR(SEG_BDA, 0))
         asm volatile(
-            "movw %%ax, %%ds\n"
+            "movw %w1, %%ds\n"
             "ljmpw *%0\n"
-            : : "m"(bda->jump_ip), "a"(SEG_BDA)
+            : : "m"(BDA_JUMP), "r"(SEG_BDA)
             );
         break;
 
     case 0x0b:
         // resume execution via IRET via 40h:0067h
         asm volatile(
-            "movw %%ax, %%ds\n"
-            "movw %0, %%sp\n"
-            "movw %1, %%ss\n"
+            "movw %w1, %%ds\n"
+            "lssw %0, %%sp\n"
             "iretw\n"
-            : : "m"(bda->jump_ip), "m"(bda->jump_cs), "a"(SEG_BDA)
+            : : "m"(BDA_JUMP), "r"(SEG_BDA)
             );
         break;
 
     case 0x0c:
         // resume execution via RETF via 40h:0067h
         asm volatile(
-            "movw %%ax, %%ds\n"
-            "movw %0, %%sp\n"
-            "movw %1, %%ss\n"
+            "movw %w1, %%ds\n"
+            "lssw %0, %%sp\n"
             "lretw\n"
-            : : "m"(bda->jump_ip), "m"(bda->jump_cs), "a"(SEG_BDA)
+            : : "m"(BDA_JUMP), "r"(SEG_BDA)
             );
         break;
+
+    default:
+        break;
     }
 
-    BX_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 VISIBLE32
-s3_resume()
+// Handle an S3 resume event
+static void
+s3_resume(void)
 {
-    dprintf(1, "In 32bit resume\n");
+    if (!CONFIG_S3_RESUME)
+        return;
 
+    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 = FARPTR_TO_OFFSET(s3_resume_vector);
-        br.cs = FARPTR_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);
 }
 
-// Ughh - some older gcc compilers have a bug which causes VISIBLE32
-// functions to not be exported as global variables.
-asm(".global s3_resume");
+// 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();
+}