aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2017-03-03 10:48:45 -0500
committerKevin O'Connor <kevin@koconnor.net>2017-03-13 11:47:36 -0400
commitc68aff57ce317d9f2d69d20eba893a10d964f316 (patch)
tree6f1cdb6c241ea0d65363e7bf9352555121cd60e8
parent1415d46dc87fd8bf1d6acd97c1ad60e893f62523 (diff)
downloadseabios-c68aff57ce317d9f2d69d20eba893a10d964f316.tar.gz
resume: Don't attempt to use generic reboot mechanisms on QEMU
On QEMU it's necessary to manually reset the BIOS memory region between 0xc0000-0x100000 on a reboot. After this manual memory reset is completed, it's not valid to use the generic reset mechanisms. Rename qemu_prep_reset() to qemu_reboot() and change the function to immediately reboot after the code memcpy. This fixes a bug that could cause code corruption on reboots - calling the udelay() function (as invoked by i8042_reboot and/or pci_reboot) was not valid after the BIOS was memcpy'd. Reported-by: "Dr. David Alan Gilbert" <dgilbert@redhat.com> Tested-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
-rw-r--r--src/fw/shadow.c14
-rw-r--r--src/hw/pci.c1
-rw-r--r--src/hw/pci.h2
-rw-r--r--src/resume.c4
-rw-r--r--src/util.h2
5 files changed, 18 insertions, 5 deletions
diff --git a/src/fw/shadow.c b/src/fw/shadow.c
index cd02d3ab..c80b266b 100644
--- a/src/fw/shadow.c
+++ b/src/fw/shadow.c
@@ -167,7 +167,7 @@ make_bios_readonly(void)
}
void
-qemu_prep_reset(void)
+qemu_reboot(void)
{
if (!CONFIG_QEMU || runningOnXen())
return;
@@ -187,4 +187,16 @@ qemu_prep_reset(void)
memcpy(hrp + 4, hrp + 4 + BIOS_SRC_OFFSET, cend - (hrp + 4));
barrier();
HaveRunPost = 0;
+ barrier();
+
+ // Request a QEMU system reset. Do the reset in this function as
+ // the BIOS code was overwritten above and not all BIOS
+ // functionality may be available.
+
+ // Attempt PCI style reset
+ outb(0x02, PORT_PCI_REBOOT);
+ outb(0x06, PORT_PCI_REBOOT);
+
+ // Next try triple faulting the CPU to force a reset
+ asm volatile("int3");
}
diff --git a/src/hw/pci.c b/src/hw/pci.c
index 506ee563..8e3d6179 100644
--- a/src/hw/pci.c
+++ b/src/hw/pci.c
@@ -12,7 +12,6 @@
#include "x86.h" // outl
#define PORT_PCI_CMD 0x0cf8
-#define PORT_PCI_REBOOT 0x0cf9
#define PORT_PCI_DATA 0x0cfc
void pci_config_writel(u16 bdf, u32 addr, u32 val)
diff --git a/src/hw/pci.h b/src/hw/pci.h
index bf504303..ee6e1968 100644
--- a/src/hw/pci.h
+++ b/src/hw/pci.h
@@ -3,6 +3,8 @@
#include "types.h" // u32
+#define PORT_PCI_REBOOT 0x0cf9
+
static inline u8 pci_bdf_to_bus(u16 bdf) {
return bdf >> 8;
}
diff --git a/src/resume.c b/src/resume.c
index 99fa34fa..fb0b8a89 100644
--- a/src/resume.c
+++ b/src/resume.c
@@ -125,8 +125,8 @@ tryReboot(void)
{
dprintf(1, "Attempting a hard reboot\n");
- // Setup for reset on qemu.
- qemu_prep_reset();
+ // Use a QEMU specific reboot on QEMU
+ qemu_reboot();
// Reboot using ACPI RESET_REG
acpi_reboot();
diff --git a/src/util.h b/src/util.h
index 336eaaf1..8269057f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -123,7 +123,7 @@ void pirtable_setup(void);
// fw/shadow.c
void make_bios_writable(void);
void make_bios_readonly(void);
-void qemu_prep_reset(void);
+void qemu_reboot(void);
// fw/smbios.c
void smbios_legacy_setup(void);