blob: 169decf7508184d0f796cb0c7d89fd11ffb5505e [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
8#include "util.h" // memcpy
9#include "pci.h" // pci_config_writeb
Kevin O'Connor9521e262008-07-04 13:04:29 -040010#include "config.h" // CONFIG_*
Kevin O'Connor2ed2f582008-11-08 15:53:36 -050011#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
Ian Campbell74c78782011-06-01 11:00:29 +010012#include "xen.h" // usingXen
Kevin O'Connorda4a6482008-06-08 13:48:06 -040013
Kevin O'Connor35284962009-07-24 21:49:26 -040014// On the emulators, the bios at 0xf0000 is also at 0xffff0000
Kevin O'Connor5bd01de2010-09-13 21:19:27 -040015#define BIOS_SRC_OFFSET 0xfff00000
Kevin O'Connor35284962009-07-24 21:49:26 -040016
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040017#define I440FX_PAM0 0x59
18
Kevin O'Connorda4a6482008-06-08 13:48:06 -040019// Enable shadowing and copy bios.
20static void
Isaku Yamahata08328e72010-07-20 16:50:45 +090021__make_bios_writable_intel(u16 bdf, u32 pam0)
Kevin O'Connorda4a6482008-06-08 13:48:06 -040022{
Kevin O'Connore7739302009-07-26 19:16:09 -040023 // Make ram from 0xc0000-0xf0000 writable
24 int clear = 0;
25 int i;
26 for (i=0; i<6; i++) {
Kevin O'Connor5bd01de2010-09-13 21:19:27 -040027 u32 pam = pam0 + 1 + i;
28 int reg = pci_config_readb(bdf, pam);
29 if (CONFIG_OPTIONROMS_DEPLOYED && (reg & 0x11) != 0x11) {
Anthony Liguori034ce4b2009-12-18 12:16:01 +010030 // Need to copy optionroms to work around qemu implementation
31 void *mem = (void*)(BUILD_ROM_START + i * 32*1024);
32 memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024);
Isaku Yamahata08328e72010-07-20 16:50:45 +090033 pci_config_writeb(bdf, pam, 0x33);
Anthony Liguori034ce4b2009-12-18 12:16:01 +010034 memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024);
35 clear = 1;
Kevin O'Connore7739302009-07-26 19:16:09 -040036 } else {
Isaku Yamahata08328e72010-07-20 16:50:45 +090037 pci_config_writeb(bdf, pam, 0x33);
Kevin O'Connore7739302009-07-26 19:16:09 -040038 }
39 }
40 if (clear)
41 memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
42
Kevin O'Connor5b8f8092009-09-20 19:47:45 -040043 // Make ram from 0xf0000-0x100000 writable
Isaku Yamahata08328e72010-07-20 16:50:45 +090044 int reg = pci_config_readb(bdf, pam0);
45 pci_config_writeb(bdf, pam0, 0x30);
Kevin O'Connor5b8f8092009-09-20 19:47:45 -040046 if (reg & 0x10)
47 // Ram already present.
48 return;
49
50 // Copy bios.
Kevin O'Connor5bd01de2010-09-13 21:19:27 -040051 extern u8 code32flat_start[], code32flat_end[];
52 memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
53 , code32flat_end - code32flat_start);
Kevin O'Connor5b8f8092009-09-20 19:47:45 -040054}
55
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040056static void
Isaku Yamahata08328e72010-07-20 16:50:45 +090057make_bios_writable_intel(u16 bdf, u32 pam0)
58{
59 int reg = pci_config_readb(bdf, pam0);
60 if (!(reg & 0x10)) {
61 // QEMU doesn't fully implement the piix shadow capabilities -
62 // if ram isn't backing the bios segment when shadowing is
63 // disabled, the code itself wont be in memory. So, run the
64 // code from the high-memory flash location.
Kevin O'Connor5bd01de2010-09-13 21:19:27 -040065 u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
Isaku Yamahata08328e72010-07-20 16:50:45 +090066 void (*func)(u16 bdf, u32 pam0) = (void*)pos;
67 func(bdf, pam0);
68 return;
69 }
70 // Ram already present - just enable writes
71 __make_bios_writable_intel(bdf, pam0);
72}
73
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040074static void
Isaku Yamahata08328e72010-07-20 16:50:45 +090075make_bios_readonly_intel(u16 bdf, u32 pam0)
76{
77 // Flush any pending writes before locking memory.
78 wbinvd();
79
80 // Write protect roms from 0xc0000-0xf0000
81 int i;
82 for (i=0; i<6; i++) {
83 u32 mem = BUILD_ROM_START + i * 32*1024;
84 u32 pam = pam0 + 1 + i;
85 if (RomEnd <= mem + 16*1024) {
86 if (RomEnd > mem)
87 pci_config_writeb(bdf, pam, 0x31);
88 break;
89 }
90 pci_config_writeb(bdf, pam, 0x11);
91 }
92
93 // Write protect 0xf0000-0x100000
94 pci_config_writeb(bdf, pam0, 0x10);
95}
96
Kevin O'Connor6e4583c2011-06-19 10:09:26 -040097static void i440fx_bios_make_writable(u16 bdf, void *arg)
98{
99 make_bios_writable_intel(bdf, I440FX_PAM0);
100}
101
102static void i440fx_bios_make_readonly(u16 bdf, void *arg)
103{
104 make_bios_readonly_intel(bdf, I440FX_PAM0);
105}
106
Isaku Yamahata08328e72010-07-20 16:50:45 +0900107static const struct pci_device_id dram_controller_make_writable_tbl[] = {
108 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
109 i440fx_bios_make_writable),
110 PCI_DEVICE_END
111};
112
Kevin O'Connor6e4583c2011-06-19 10:09:26 -0400113static const struct pci_device_id dram_controller_make_readonly_tbl[] = {
114 PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
115 i440fx_bios_make_readonly),
116 PCI_DEVICE_END
117};
118
Kevin O'Connor5b8f8092009-09-20 19:47:45 -0400119// Make the 0xc0000-0x100000 area read/writable.
120void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500121make_bios_writable(void)
Kevin O'Connor5b8f8092009-09-20 19:47:45 -0400122{
Ian Campbell74c78782011-06-01 11:00:29 +0100123 if (CONFIG_COREBOOT || usingXen())
Kevin O'Connor5b8f8092009-09-20 19:47:45 -0400124 return;
125
126 dprintf(3, "enabling shadow ram\n");
127
Kevin O'Connor5bd01de2010-09-13 21:19:27 -0400128 // at this point, statically allocated variables can't be written.
Isaku Yamahata08328e72010-07-20 16:50:45 +0900129 // so stack should be used.
130
Kevin O'Connor5b8f8092009-09-20 19:47:45 -0400131 // Locate chip controlling ram shadowing.
Isaku Yamahata08328e72010-07-20 16:50:45 +0900132 int bdf = pci_find_init_device(dram_controller_make_writable_tbl, NULL);
Kevin O'Connor5b8f8092009-09-20 19:47:45 -0400133 if (bdf < 0) {
134 dprintf(1, "Unable to unlock ram - bridge not found\n");
Kevin O'Connor35284962009-07-24 21:49:26 -0400135 }
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400136}
137
138// Make the BIOS code segment area (0xf0000) read-only.
139void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -0500140make_bios_readonly(void)
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400141{
Ian Campbell74c78782011-06-01 11:00:29 +0100142 if (CONFIG_COREBOOT || usingXen())
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400143 return;
144
145 dprintf(3, "locking shadow ram\n");
Isaku Yamahata08328e72010-07-20 16:50:45 +0900146 int bdf = pci_find_init_device(dram_controller_make_readonly_tbl, NULL);
Kevin O'Connorbe19cdc2008-11-09 15:33:47 -0500147 if (bdf < 0) {
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400148 dprintf(1, "Unable to lock ram - bridge not found\n");
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400149 }
Kevin O'Connorda4a6482008-06-08 13:48:06 -0400150}
Kevin O'Connor244caf82010-09-15 21:48:16 -0400151
152void
153qemu_prep_reset(void)
154{
155 if (CONFIG_COREBOOT)
156 return;
157 // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
158 // reset, so do that manually before invoking a hard reset.
159 make_bios_writable();
160 extern u8 code32flat_start[], code32flat_end[];
161 memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
162 , code32flat_end - code32flat_start);
163}