Use defines for PCI ids.
[seabios.git] / src / shadow.c
1 // Support for enabling/disabling BIOS ram shadowing.
2 //
3 // Copyright (C) 2008  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 GPLv3 license.
7
8 #include "util.h" // memcpy
9 #include "pci.h" // pci_config_writeb
10 #include "config.h" // CONFIG_*
11
12 // Test if 'addr' is in the range from 'start'..'start+size'
13 #define IN_RANGE(addr, start, size) ({   \
14             u32 __addr = (addr);         \
15             u32 __start = (start);       \
16             u32 __size = (size);         \
17             (__addr - __start < __size); \
18         })
19
20 // Enable shadowing and copy bios.
21 static void
22 copy_bios(PCIDevice d)
23 {
24     int v = pci_config_readb(d, 0x59);
25     v |= 0x30;
26     pci_config_writeb(d, 0x59, v);
27     memcpy((void *)BUILD_BIOS_ADDR, (void *)BUILD_BIOS_TMP_ADDR
28            , BUILD_BIOS_SIZE);
29 }
30
31 // Make the BIOS code segment area (0xf0000) writable.
32 void
33 make_bios_writable()
34 {
35     if (CONFIG_COREBOOT)
36         return;
37
38     dprintf(3, "enabling shadow ram\n");
39
40     // Locate chip controlling ram shadowing.
41     PCIDevice d;
42     int ret = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441
43                               , 0, &d);
44     if (ret) {
45         dprintf(1, "Unable to unlock ram - bridge not found\n");
46         return;
47     }
48
49     // Copy the bios to a temporary area.
50     memcpy((void *)BUILD_BIOS_TMP_ADDR, (void *)BUILD_BIOS_ADDR
51            , BUILD_BIOS_SIZE);
52
53     // Enable shadowing and copy bios.
54     if (IN_RANGE((u32)copy_bios, BUILD_BIOS_ADDR, BUILD_BIOS_SIZE)) {
55         // Jump to shadow enable function - use the copy in the
56         // temporary storage area so that memory does not change under
57         // the executing code.
58         u32 pos = (u32)copy_bios - BUILD_BIOS_ADDR + BUILD_BIOS_TMP_ADDR;
59         void (*func)(PCIDevice) = (void*)pos;
60         func(d);
61     } else {
62         copy_bios(d);
63     }
64
65     // Clear the temporary area.
66     memset((void *)BUILD_BIOS_TMP_ADDR, 0, BUILD_BIOS_SIZE);
67 }
68
69 // Make the BIOS code segment area (0xf0000) read-only.
70 void
71 make_bios_readonly()
72 {
73     if (CONFIG_COREBOOT)
74         return;
75
76     dprintf(3, "locking shadow ram\n");
77
78     PCIDevice d;
79     int ret = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441
80                               , 0, &d);
81     if (ret) {
82         dprintf(1, "Unable to lock ram - bridge not found\n");
83         return;
84     }
85
86     wbinvd();
87     int v = pci_config_readb(d, 0x59);
88     v = (v & 0x0f) | (0x10);
89     pci_config_writeb(d, 0x59, v);
90 }