Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


fix potential overflow condition in VMX assist
[palacios.git] / bios / seabios / src / shadow.c
1 // Support for enabling/disabling BIOS ram shadowing.
2 //
3 // Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2006 Fabrice Bellard
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "util.h" // memcpy
9 #include "pci.h" // pci_config_writeb
10 #include "config.h" // CONFIG_*
11 #include "pci_ids.h" // PCI_VENDOR_ID_INTEL
12 #include "pci_regs.h" // PCI_VENDOR_ID
13 #include "xen.h" // usingXen
14
15 // On the emulators, the bios at 0xf0000 is also at 0xffff0000
16 #define BIOS_SRC_OFFSET 0xfff00000
17
18 #define I440FX_PAM0     0x59
19
20 // Enable shadowing and copy bios.
21 static void
22 __make_bios_writable_intel(u16 bdf, u32 pam0)
23 {
24     // Make ram from 0xc0000-0xf0000 writable
25     int clear = 0;
26     int i;
27     for (i=0; i<6; i++) {
28         u32 pam = pam0 + 1 + i;
29         int reg = pci_config_readb(bdf, pam);
30         if (CONFIG_OPTIONROMS_DEPLOYED && (reg & 0x11) != 0x11) {
31             // Need to copy optionroms to work around qemu implementation
32             void *mem = (void*)(BUILD_ROM_START + i * 32*1024);
33             memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024);
34             pci_config_writeb(bdf, pam, 0x33);
35             memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024);
36             clear = 1;
37         } else {
38             pci_config_writeb(bdf, pam, 0x33);
39         }
40     }
41     if (clear)
42         memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
43
44     // Make ram from 0xf0000-0x100000 writable
45     int reg = pci_config_readb(bdf, pam0);
46     pci_config_writeb(bdf, pam0, 0x30);
47     if (reg & 0x10)
48         // Ram already present.
49         return;
50
51     // Copy bios.
52     extern u8 code32flat_start[], code32flat_end[];
53     memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
54            , code32flat_end - code32flat_start);
55 }
56
57 static void
58 make_bios_writable_intel(u16 bdf, u32 pam0)
59 {
60     int reg = pci_config_readb(bdf, pam0);
61     if (!(reg & 0x10)) {
62         // QEMU doesn't fully implement the piix shadow capabilities -
63         // if ram isn't backing the bios segment when shadowing is
64         // disabled, the code itself wont be in memory.  So, run the
65         // code from the high-memory flash location.
66         u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
67         void (*func)(u16 bdf, u32 pam0) = (void*)pos;
68         func(bdf, pam0);
69         return;
70     }
71     // Ram already present - just enable writes
72     __make_bios_writable_intel(bdf, pam0);
73 }
74
75 static void
76 make_bios_readonly_intel(u16 bdf, u32 pam0)
77 {
78     // Flush any pending writes before locking memory.
79     wbinvd();
80
81     // Write protect roms from 0xc0000-0xf0000
82     int i;
83     for (i=0; i<6; i++) {
84         u32 mem = BUILD_ROM_START + i * 32*1024;
85         u32 pam = pam0 + 1 + i;
86         if (RomEnd <= mem + 16*1024) {
87             if (RomEnd > mem)
88                 pci_config_writeb(bdf, pam, 0x31);
89             break;
90         }
91         pci_config_writeb(bdf, pam, 0x11);
92     }
93
94     // Write protect 0xf0000-0x100000
95     pci_config_writeb(bdf, pam0, 0x10);
96 }
97
98 static void i440fx_bios_make_readonly(struct pci_device *pci, void *arg)
99 {
100     make_bios_readonly_intel(pci->bdf, I440FX_PAM0);
101 }
102
103 static const struct pci_device_id dram_controller_make_readonly_tbl[] = {
104     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
105                i440fx_bios_make_readonly),
106     PCI_DEVICE_END
107 };
108
109 // Make the 0xc0000-0x100000 area read/writable.
110 void
111 make_bios_writable(void)
112 {
113     if (CONFIG_COREBOOT || usingXen())
114         return;
115
116     dprintf(3, "enabling shadow ram\n");
117
118     // At this point, statically allocated variables can't be written,
119     // so do this search manually.
120     int bdf;
121     foreachbdf(bdf, 0) {
122         u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
123         u16 vendor = vendev & 0xffff, device = vendev >> 16;
124         if (vendor == PCI_VENDOR_ID_INTEL
125             && device == PCI_DEVICE_ID_INTEL_82441) {
126             make_bios_writable_intel(bdf, I440FX_PAM0);
127             return;
128         }
129     }
130     dprintf(1, "Unable to unlock ram - bridge not found\n");
131 }
132
133 // Make the BIOS code segment area (0xf0000) read-only.
134 void
135 make_bios_readonly(void)
136 {
137     if (CONFIG_COREBOOT || usingXen())
138         return;
139
140     dprintf(3, "locking shadow ram\n");
141     struct pci_device *pci = pci_find_init_device(
142         dram_controller_make_readonly_tbl, NULL);
143     if (!pci)
144         dprintf(1, "Unable to lock ram - bridge not found\n");
145 }
146
147 void
148 qemu_prep_reset(void)
149 {
150     if (CONFIG_COREBOOT)
151         return;
152     // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
153     // reset, so do that manually before invoking a hard reset.
154     make_bios_writable();
155     extern u8 code32flat_start[], code32flat_end[];
156     memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
157            , code32flat_end - code32flat_start);
158 }