blob: 987eaf4ab205c36a82774fc3851d8d0f9af3e5d0 [file] [log] [blame]
Kevin O'Connorda4a6482008-06-08 13:48:06 -04001// Support for enabling/disabling BIOS ram shadowing.
2//
Kevin O'Connor5bd01de2010-09-13 21:19:27 -04003// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connorda4a6482008-06-08 13:48:06 -04004// Copyright (C) 2006 Fabrice Bellard
5//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05006// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connorda4a6482008-06-08 13:48:06 -04007
Kevin O'Connor9521e262008-07-04 13:04:29 -04008#include "config.h" // CONFIG_*
Kevin O'Connor2d2fa312013-09-14 21:55:26 -04009#include "dev-q35.h" // PCI_VENDOR_ID_INTEL
Paolo Bonzini40d03122014-05-15 13:22:26 +020010#include "dev-piix.h" // I440FX_PAM0
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040011#include "hw/pci.h" // pci_config_writeb
Kevin O'Connor5d369d82013-09-02 20:48:46 -040012#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
13#include "hw/pci_regs.h" // PCI_VENDOR_ID
Kevin O'Connor9dea5902013-09-14 20:23:54 -040014#include "malloc.h" // rom_get_last
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040015#include "output.h" // dprintf
16#include "paravirt.h" // runningOnXen
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040017#include "string.h" // memset
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040018#include "util.h" // make_bios_writable
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040019#include "x86.h" // wbinvd
Kevin O'Connorda4a6482008-06-08 13:48:06 -040020
Kevin O'Connor35284962009-07-24 21:49:26 -040021// On the emulators, the bios at 0xf0000 is also at 0xffff0000
Kevin O'Connor5bd01de2010-09-13 21:19:27 -040022#define BIOS_SRC_OFFSET 0xfff00000
Kevin O'Connor35284962009-07-24 21:49:26 -040023
Kevin O'Connord449a112016-04-01 15:45:29 -040024union pamdata_u {
25 u8 data8[8];
26 u32 data32[2];
27};
28
Kevin O'Connorda4a6482008-06-08 13:48:06 -040029// Enable shadowing and copy bios.
30static void
Isaku Yamahata08328e72010-07-20 16:50:45 +090031__make_bios_writable_intel(u16 bdf, u32 pam0)
Kevin O'Connorda4a6482008-06-08 13:48:06 -040032{
Kevin O'Connord449a112016-04-01 15:45:29 -040033 // Read in current PAM settings from pci config space
34 union pamdata_u pamdata;
35 pamdata.data32[0] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4));
36 pamdata.data32[1] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4) + 4);
37 u8 *pam = &pamdata.data8[pam0 & 0x03];
38
Kevin O'Connore7739302009-07-26 19:16:09 -040039 // Make ram from 0xc0000-0xf0000 writable
Kevin O'Connore7739302009-07-26 19:16:09 -040040 int i;
Kevin O'Connord449a112016-04-01 15:45:29 -040041 for (i=0; i<6; i++)
42 pam[i + 1] = 0x33;
Kevin O'Connore7739302009-07-26 19:16:09 -040043
Kevin O'Connor5b8f8092009-09-20 19:47:45 -040044 // Make ram from 0xf0000-0x100000 writable
Kevin O'Connord449a112016-04-01 15:45:29 -040045 int ram_present = pam[0] & 0x10;
46 pam[0] = 0x30;
Kevin O'Connor5b8f8092009-09-20 19:47:45 -040047
Kevin O'Connord449a112016-04-01 15:45:29 -040048 // Write PAM settings back to pci config space
49 pci_config_writel(bdf, ALIGN_DOWN(pam0, 4), pamdata.data32[0]);
50 pci_config_writel(bdf, ALIGN_DOWN(pam0, 4) + 4, pamdata.data32[1]);
51
52 if (!ram_present)
53 // Copy bios.
54 memcpy(VSYMBOL(code32flat_start)
55 , VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET
56 , SYMBOL(code32flat_end) - SYMBOL(code32flat_start));
Kevin O'Connor5b8f8092009-09-20 19:47:45 -040057}
58
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040059static void
Isaku Yamahata08328e72010-07-20 16:50:45 +090060make_bios_writable_intel(u16 bdf, u32 pam0)
61{
62 int reg = pci_config_readb(bdf, pam0);
63 if (!(reg & 0x10)) {
64 // QEMU doesn't fully implement the piix shadow capabilities -
65 // if ram isn't backing the bios segment when shadowing is
Stefan Weil6bcacf72015-10-02 08:46:40 +020066 // disabled, the code itself won't be in memory. So, run the
Isaku Yamahata08328e72010-07-20 16:50:45 +090067 // code from the high-memory flash location.
Kevin O'Connor5bd01de2010-09-13 21:19:27 -040068 u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
Isaku Yamahata08328e72010-07-20 16:50:45 +090069 void (*func)(u16 bdf, u32 pam0) = (void*)pos;
70 func(bdf, pam0);
71 return;
72 }
73 // Ram already present - just enable writes
74 __make_bios_writable_intel(bdf, pam0);
75}
76
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040077static void
Isaku Yamahata08328e72010-07-20 16:50:45 +090078make_bios_readonly_intel(u16 bdf, u32 pam0)
79{
80 // Flush any pending writes before locking memory.
81 wbinvd();
82
Kevin O'Connord449a112016-04-01 15:45:29 -040083 // Read in current PAM settings from pci config space
84 union pamdata_u pamdata;
85 pamdata.data32[0] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4));
86 pamdata.data32[1] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4) + 4);
87 u8 *pam = &pamdata.data8[pam0 & 0x03];
88
Isaku Yamahata08328e72010-07-20 16:50:45 +090089 // Write protect roms from 0xc0000-0xf0000
Kevin O'Connor2b0fb8c2013-08-07 23:03:47 -040090 u32 romlast = BUILD_BIOS_ADDR, rommax = BUILD_BIOS_ADDR;
Kevin O'Connorc98424c2013-07-21 16:38:18 -040091 if (CONFIG_WRITABLE_UPPERMEMORY)
92 romlast = rom_get_last();
Kevin O'Connor2b0fb8c2013-08-07 23:03:47 -040093 if (CONFIG_MALLOC_UPPERMEMORY)
94 rommax = rom_get_max();
Isaku Yamahata08328e72010-07-20 16:50:45 +090095 int i;
96 for (i=0; i<6; i++) {
97 u32 mem = BUILD_ROM_START + i * 32*1024;
Kevin O'Connorc98424c2013-07-21 16:38:18 -040098 if (romlast < mem + 16*1024 || rommax < mem + 32*1024) {
99 if (romlast >= mem && rommax >= mem + 16*1024)
Kevin O'Connord449a112016-04-01 15:45:29 -0400100 pam[i + 1] = 0x31;
Isaku Yamahata08328e72010-07-20 16:50:45 +0900101 break;
102 }
Kevin O'Connord449a112016-04-01 15:45:29 -0400103 pam[i + 1] = 0x11;
Isaku Yamahata08328e72010-07-20 16:50:45 +0900104 }
105
106 // Write protect 0xf0000-0x100000
Kevin O'Connord449a112016-04-01 15:45:29 -0400107 pam[0] = 0x10;
108
109 // Write PAM settings back to pci config space
110 pci_config_writel(bdf, ALIGN_DOWN(pam0, 4), pamdata.data32[0]);
111 pci_config_writel(bdf, ALIGN_DOWN(pam0, 4) + 4, pamdata.data32[1]);
Isaku Yamahata08328e72010-07-20 16:50:45 +0900112}
113
Kevin O'Connor96d4c432013-03-08 19:31:14 -0500114static int ShadowBDF = -1;
Kevin O'Connor6e4583c2011-06-19 10:09:26 -0400115
Kevin O'Connor5b8f8092009-09-20 19:47:45 -0400116// Make the 0xc0000-0x100000 area read/writable.
117void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500118make_bios_writable(void)
Kevin O'Connor5b8f8092009-09-20 19:47:45 -0400119{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500120 if (!CONFIG_QEMU || runningOnXen())
Kevin O'Connor5b8f8092009-09-20 19:47:45 -0400121 return;
122
123 dprintf(3, "enabling shadow ram\n");
124
Kevin O'Connorfaf6a4e2011-06-21 21:22:01 -0400125 // At this point, statically allocated variables can't be written,
126 // so do this search manually.
Kevin O'Connor2b333e42011-07-02 14:49:41 -0400127 int bdf;
128 foreachbdf(bdf, 0) {
Kevin O'Connorfaf6a4e2011-06-21 21:22:01 -0400129 u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
130 u16 vendor = vendev & 0xffff, device = vendev >> 16;
131 if (vendor == PCI_VENDOR_ID_INTEL
132 && device == PCI_DEVICE_ID_INTEL_82441) {
133 make_bios_writable_intel(bdf, I440FX_PAM0);
Kevin O'Connora48f6022016-01-12 14:22:33 -0500134 code_mutable_preinit();
Kevin O'Connor96d4c432013-03-08 19:31:14 -0500135 ShadowBDF = bdf;
Kevin O'Connorfaf6a4e2011-06-21 21:22:01 -0400136 return;
137 }
Isaku Yamahata72a590e2012-11-28 10:17:33 +0100138 if (vendor == PCI_VENDOR_ID_INTEL
139 && device == PCI_DEVICE_ID_INTEL_Q35_MCH) {
140 make_bios_writable_intel(bdf, Q35_HOST_BRIDGE_PAM0);
Kevin O'Connora48f6022016-01-12 14:22:33 -0500141 code_mutable_preinit();
Kevin O'Connor96d4c432013-03-08 19:31:14 -0500142 ShadowBDF = bdf;
Isaku Yamahata72a590e2012-11-28 10:17:33 +0100143 return;
144 }
Kevin O'Connor35284962009-07-24 21:49:26 -0400145 }
Kevin O'Connorfaf6a4e2011-06-21 21:22:01 -0400146 dprintf(1, "Unable to unlock ram - bridge not found\n");
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400147}
148
149// Make the BIOS code segment area (0xf0000) read-only.
150void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500151make_bios_readonly(void)
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400152{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500153 if (!CONFIG_QEMU || runningOnXen())
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400154 return;
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400155 dprintf(3, "locking shadow ram\n");
Kevin O'Connor96d4c432013-03-08 19:31:14 -0500156
157 if (ShadowBDF < 0) {
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400158 dprintf(1, "Unable to lock ram - bridge not found\n");
Kevin O'Connor96d4c432013-03-08 19:31:14 -0500159 return;
160 }
161
162 u16 device = pci_config_readw(ShadowBDF, PCI_DEVICE_ID);
163 if (device == PCI_DEVICE_ID_INTEL_82441)
164 make_bios_readonly_intel(ShadowBDF, I440FX_PAM0);
165 else
166 make_bios_readonly_intel(ShadowBDF, Q35_HOST_BRIDGE_PAM0);
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400167}
Kevin O'Connor244caf82010-09-15 21:48:16 -0400168
169void
Kevin O'Connorc68aff52017-03-03 10:48:45 -0500170qemu_reboot(void)
Kevin O'Connor244caf82010-09-15 21:48:16 -0400171{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500172 if (!CONFIG_QEMU || runningOnXen())
Kevin O'Connor244caf82010-09-15 21:48:16 -0400173 return;
174 // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
175 // reset, so do that manually before invoking a hard reset.
Kevin O'Connorb837e682015-11-09 15:00:19 -0500176 void *cstart = VSYMBOL(code32flat_start), *cend = VSYMBOL(code32flat_end);
177 void *hrp = &HaveRunPost;
178 if (readl(hrp + BIOS_SRC_OFFSET)) {
Kevin O'Connor42812e02018-02-22 20:29:27 -0500179 // There isn't a pristine copy of the BIOS at 0xffff0000 to copy
180 if (HaveRunPost == 3) {
181 // In a reboot loop. Try to shutdown the machine instead.
182 dprintf(1, "Unable to hard-reboot machine - attempting shutdown.\n");
183 apm_shutdown();
184 }
185 make_bios_writable();
186 HaveRunPost = 3;
187 } else {
188 // Copy the BIOS making sure to only reset HaveRunPost at end
189 make_bios_writable();
190 memcpy(cstart, cstart + BIOS_SRC_OFFSET, hrp - cstart);
191 memcpy(hrp + 4, hrp + 4 + BIOS_SRC_OFFSET, cend - (hrp + 4));
192 barrier();
193 HaveRunPost = 0;
194 barrier();
Kevin O'Connorb837e682015-11-09 15:00:19 -0500195 }
Kevin O'Connorc68aff52017-03-03 10:48:45 -0500196
197 // Request a QEMU system reset. Do the reset in this function as
198 // the BIOS code was overwritten above and not all BIOS
199 // functionality may be available.
200
201 // Attempt PCI style reset
202 outb(0x02, PORT_PCI_REBOOT);
203 outb(0x06, PORT_PCI_REBOOT);
204
205 // Next try triple faulting the CPU to force a reset
206 asm volatile("int3");
Kevin O'Connor244caf82010-09-15 21:48:16 -0400207}