Try to hard-reboot on rerun of post even on emulators.
[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 "dev-i440fx.h"
13
14 // On the emulators, the bios at 0xf0000 is also at 0xffff0000
15 #define BIOS_SRC_OFFSET 0xfff00000
16
17 // Enable shadowing and copy bios.
18 static void
19 __make_bios_writable_intel(u16 bdf, u32 pam0)
20 {
21     // Make ram from 0xc0000-0xf0000 writable
22     int clear = 0;
23     int i;
24     for (i=0; i<6; i++) {
25         u32 pam = pam0 + 1 + i;
26         int reg = pci_config_readb(bdf, pam);
27         if (CONFIG_OPTIONROMS_DEPLOYED && (reg & 0x11) != 0x11) {
28             // Need to copy optionroms to work around qemu implementation
29             void *mem = (void*)(BUILD_ROM_START + i * 32*1024);
30             memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024);
31             pci_config_writeb(bdf, pam, 0x33);
32             memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024);
33             clear = 1;
34         } else {
35             pci_config_writeb(bdf, pam, 0x33);
36         }
37     }
38     if (clear)
39         memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
40
41     // Make ram from 0xf0000-0x100000 writable
42     int reg = pci_config_readb(bdf, pam0);
43     pci_config_writeb(bdf, pam0, 0x30);
44     if (reg & 0x10)
45         // Ram already present.
46         return;
47
48     // Copy bios.
49     extern u8 code32flat_start[], code32flat_end[];
50     memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
51            , code32flat_end - code32flat_start);
52 }
53
54 void
55 make_bios_writable_intel(u16 bdf, u32 pam0)
56 {
57     int reg = pci_config_readb(bdf, pam0);
58     if (!(reg & 0x10)) {
59         // QEMU doesn't fully implement the piix shadow capabilities -
60         // if ram isn't backing the bios segment when shadowing is
61         // disabled, the code itself wont be in memory.  So, run the
62         // code from the high-memory flash location.
63         u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
64         void (*func)(u16 bdf, u32 pam0) = (void*)pos;
65         func(bdf, pam0);
66         return;
67     }
68     // Ram already present - just enable writes
69     __make_bios_writable_intel(bdf, pam0);
70 }
71
72 void
73 make_bios_readonly_intel(u16 bdf, u32 pam0)
74 {
75     // Flush any pending writes before locking memory.
76     wbinvd();
77
78     // Write protect roms from 0xc0000-0xf0000
79     int i;
80     for (i=0; i<6; i++) {
81         u32 mem = BUILD_ROM_START + i * 32*1024;
82         u32 pam = pam0 + 1 + i;
83         if (RomEnd <= mem + 16*1024) {
84             if (RomEnd > mem)
85                 pci_config_writeb(bdf, pam, 0x31);
86             break;
87         }
88         pci_config_writeb(bdf, pam, 0x11);
89     }
90
91     // Write protect 0xf0000-0x100000
92     pci_config_writeb(bdf, pam0, 0x10);
93 }
94
95 static const struct pci_device_id dram_controller_make_writable_tbl[] = {
96     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
97                i440fx_bios_make_writable),
98     PCI_DEVICE_END
99 };
100
101 // Make the 0xc0000-0x100000 area read/writable.
102 void
103 make_bios_writable(void)
104 {
105     if (CONFIG_COREBOOT)
106         return;
107
108     dprintf(3, "enabling shadow ram\n");
109
110     // at this point, statically allocated variables can't be written.
111     // so stack should be used.
112
113     // Locate chip controlling ram shadowing.
114     int bdf = pci_find_init_device(dram_controller_make_writable_tbl, NULL);
115     if (bdf < 0) {
116         dprintf(1, "Unable to unlock ram - bridge not found\n");
117     }
118 }
119
120 static const struct pci_device_id dram_controller_make_readonly_tbl[] = {
121     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
122                i440fx_bios_make_readonly),
123     PCI_DEVICE_END
124 };
125
126 // Make the BIOS code segment area (0xf0000) read-only.
127 void
128 make_bios_readonly(void)
129 {
130     if (CONFIG_COREBOOT)
131         return;
132
133     dprintf(3, "locking shadow ram\n");
134     int bdf = pci_find_init_device(dram_controller_make_readonly_tbl, NULL);
135     if (bdf < 0) {
136         dprintf(1, "Unable to lock ram - bridge not found\n");
137     }
138 }
139
140 void
141 qemu_prep_reset(void)
142 {
143     if (CONFIG_COREBOOT)
144         return;
145     // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
146     // reset, so do that manually before invoking a hard reset.
147     make_bios_writable();
148     extern u8 code32flat_start[], code32flat_end[];
149     memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
150            , code32flat_end - code32flat_start);
151 }