Remove dev-i440fx.c/h - move code closer to its callers.
[seabios.git] / 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 "xen.h" // usingXen
13
14 // On the emulators, the bios at 0xf0000 is also at 0xffff0000
15 #define BIOS_SRC_OFFSET 0xfff00000
16
17 #define I440FX_PAM0     0x59
18
19 // Enable shadowing and copy bios.
20 static void
21 __make_bios_writable_intel(u16 bdf, u32 pam0)
22 {
23     // Make ram from 0xc0000-0xf0000 writable
24     int clear = 0;
25     int i;
26     for (i=0; i<6; i++) {
27         u32 pam = pam0 + 1 + i;
28         int reg = pci_config_readb(bdf, pam);
29         if (CONFIG_OPTIONROMS_DEPLOYED && (reg & 0x11) != 0x11) {
30             // 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);
33             pci_config_writeb(bdf, pam, 0x33);
34             memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024);
35             clear = 1;
36         } else {
37             pci_config_writeb(bdf, pam, 0x33);
38         }
39     }
40     if (clear)
41         memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
42
43     // Make ram from 0xf0000-0x100000 writable
44     int reg = pci_config_readb(bdf, pam0);
45     pci_config_writeb(bdf, pam0, 0x30);
46     if (reg & 0x10)
47         // Ram already present.
48         return;
49
50     // Copy bios.
51     extern u8 code32flat_start[], code32flat_end[];
52     memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
53            , code32flat_end - code32flat_start);
54 }
55
56 static void
57 make_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.
65         u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
66         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
74 static void
75 make_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
97 static void i440fx_bios_make_writable(u16 bdf, void *arg)
98 {
99     make_bios_writable_intel(bdf, I440FX_PAM0);
100 }
101
102 static void i440fx_bios_make_readonly(u16 bdf, void *arg)
103 {
104     make_bios_readonly_intel(bdf, I440FX_PAM0);
105 }
106
107 static 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
113 static 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
119 // Make the 0xc0000-0x100000 area read/writable.
120 void
121 make_bios_writable(void)
122 {
123     if (CONFIG_COREBOOT || usingXen())
124         return;
125
126     dprintf(3, "enabling shadow ram\n");
127
128     // at this point, statically allocated variables can't be written.
129     // so stack should be used.
130
131     // Locate chip controlling ram shadowing.
132     int bdf = pci_find_init_device(dram_controller_make_writable_tbl, NULL);
133     if (bdf < 0) {
134         dprintf(1, "Unable to unlock ram - bridge not found\n");
135     }
136 }
137
138 // Make the BIOS code segment area (0xf0000) read-only.
139 void
140 make_bios_readonly(void)
141 {
142     if (CONFIG_COREBOOT || usingXen())
143         return;
144
145     dprintf(3, "locking shadow ram\n");
146     int bdf = pci_find_init_device(dram_controller_make_readonly_tbl, NULL);
147     if (bdf < 0) {
148         dprintf(1, "Unable to lock ram - bridge not found\n");
149     }
150 }
151
152 void
153 qemu_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 }