Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : #include <linux/sched.h>
3 : : #include <linux/mm.h>
4 : : #include <linux/uaccess.h>
5 : : #include <linux/mmzone.h>
6 : : #include <linux/ioport.h>
7 : : #include <linux/seq_file.h>
8 : : #include <linux/console.h>
9 : : #include <linux/init.h>
10 : : #include <linux/edd.h>
11 : : #include <linux/dmi.h>
12 : : #include <linux/pfn.h>
13 : : #include <linux/pci.h>
14 : : #include <linux/export.h>
15 : :
16 : : #include <asm/probe_roms.h>
17 : : #include <asm/pci-direct.h>
18 : : #include <asm/e820/api.h>
19 : : #include <asm/mmzone.h>
20 : : #include <asm/setup.h>
21 : : #include <asm/sections.h>
22 : : #include <asm/io.h>
23 : : #include <asm/setup_arch.h>
24 : :
25 : : static struct resource system_rom_resource = {
26 : : .name = "System ROM",
27 : : .start = 0xf0000,
28 : : .end = 0xfffff,
29 : : .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
30 : : };
31 : :
32 : : static struct resource extension_rom_resource = {
33 : : .name = "Extension ROM",
34 : : .start = 0xe0000,
35 : : .end = 0xeffff,
36 : : .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
37 : : };
38 : :
39 : : static struct resource adapter_rom_resources[] = { {
40 : : .name = "Adapter ROM",
41 : : .start = 0xc8000,
42 : : .end = 0,
43 : : .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
44 : : }, {
45 : : .name = "Adapter ROM",
46 : : .start = 0,
47 : : .end = 0,
48 : : .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
49 : : }, {
50 : : .name = "Adapter ROM",
51 : : .start = 0,
52 : : .end = 0,
53 : : .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
54 : : }, {
55 : : .name = "Adapter ROM",
56 : : .start = 0,
57 : : .end = 0,
58 : : .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
59 : : }, {
60 : : .name = "Adapter ROM",
61 : : .start = 0,
62 : : .end = 0,
63 : : .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
64 : : }, {
65 : : .name = "Adapter ROM",
66 : : .start = 0,
67 : : .end = 0,
68 : : .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
69 : : } };
70 : :
71 : : static struct resource video_rom_resource = {
72 : : .name = "Video ROM",
73 : : .start = 0xc0000,
74 : : .end = 0xc7fff,
75 : : .flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
76 : : };
77 : :
78 : : /* does this oprom support the given pci device, or any of the devices
79 : : * that the driver supports?
80 : : */
81 : 0 : static bool match_id(struct pci_dev *pdev, unsigned short vendor, unsigned short device)
82 : : {
83 : 0 : struct pci_driver *drv = pdev->driver;
84 : 0 : const struct pci_device_id *id;
85 : :
86 [ # # # # ]: 0 : if (pdev->vendor == vendor && pdev->device == device)
87 : : return true;
88 : :
89 [ # # # # : 0 : for (id = drv ? drv->id_table : NULL; id && id->vendor; id++)
# # ]
90 [ # # # # ]: 0 : if (id->vendor == vendor && id->device == device)
91 : : break;
92 : :
93 [ # # # # ]: 0 : return id && id->vendor;
94 : : }
95 : :
96 : 0 : static bool probe_list(struct pci_dev *pdev, unsigned short vendor,
97 : : const unsigned char *rom_list)
98 : : {
99 : 0 : unsigned short device;
100 : :
101 : 0 : do {
102 [ # # ]: 0 : if (probe_kernel_address(rom_list, device) != 0)
103 : 0 : device = 0;
104 : :
105 [ # # # # ]: 0 : if (device && match_id(pdev, vendor, device))
106 : : break;
107 : :
108 : 0 : rom_list += 2;
109 [ # # ]: 0 : } while (device);
110 : :
111 : 0 : return !!device;
112 : : }
113 : :
114 : 0 : static struct resource *find_oprom(struct pci_dev *pdev)
115 : : {
116 : 0 : struct resource *oprom = NULL;
117 : 0 : int i;
118 : :
119 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(adapter_rom_resources); i++) {
120 : 0 : struct resource *res = &adapter_rom_resources[i];
121 : 0 : unsigned short offset, vendor, device, list, rev;
122 : 0 : const unsigned char *rom;
123 : :
124 [ # # ]: 0 : if (res->end == 0)
125 : : break;
126 : :
127 : 0 : rom = isa_bus_to_virt(res->start);
128 [ # # ]: 0 : if (probe_kernel_address(rom + 0x18, offset) != 0)
129 : 0 : continue;
130 : :
131 [ # # ]: 0 : if (probe_kernel_address(rom + offset + 0x4, vendor) != 0)
132 : 0 : continue;
133 : :
134 [ # # ]: 0 : if (probe_kernel_address(rom + offset + 0x6, device) != 0)
135 : 0 : continue;
136 : :
137 [ # # ]: 0 : if (match_id(pdev, vendor, device)) {
138 : : oprom = res;
139 : : break;
140 : : }
141 : :
142 [ # # # # ]: 0 : if (probe_kernel_address(rom + offset + 0x8, list) == 0 &&
143 : 0 : probe_kernel_address(rom + offset + 0xc, rev) == 0 &&
144 [ # # # # : 0 : rev >= 3 && list &&
# # ]
145 : 0 : probe_list(pdev, vendor, rom + offset + list)) {
146 : : oprom = res;
147 : : break;
148 : : }
149 : : }
150 : :
151 : 0 : return oprom;
152 : : }
153 : :
154 : 0 : void __iomem *pci_map_biosrom(struct pci_dev *pdev)
155 : : {
156 : 0 : struct resource *oprom = find_oprom(pdev);
157 : :
158 [ # # ]: 0 : if (!oprom)
159 : : return NULL;
160 : :
161 : 0 : return ioremap(oprom->start, resource_size(oprom));
162 : : }
163 : : EXPORT_SYMBOL(pci_map_biosrom);
164 : :
165 : 0 : void pci_unmap_biosrom(void __iomem *image)
166 : : {
167 : 0 : iounmap(image);
168 : 0 : }
169 : : EXPORT_SYMBOL(pci_unmap_biosrom);
170 : :
171 : 0 : size_t pci_biosrom_size(struct pci_dev *pdev)
172 : : {
173 : 0 : struct resource *oprom = find_oprom(pdev);
174 : :
175 [ # # ]: 0 : return oprom ? resource_size(oprom) : 0;
176 : : }
177 : : EXPORT_SYMBOL(pci_biosrom_size);
178 : :
179 : : #define ROMSIGNATURE 0xaa55
180 : :
181 : 862 : static int __init romsignature(const unsigned char *rom)
182 : : {
183 : 862 : const unsigned short * const ptr = (const unsigned short *)rom;
184 : 862 : unsigned short sig;
185 : :
186 [ + - + + ]: 862 : return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE;
187 : : }
188 : :
189 : 44 : static int __init romchecksum(const unsigned char *rom, unsigned long length)
190 : : {
191 : 44 : unsigned char sum, c;
192 : :
193 [ + + + - ]: 726572 : for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--)
194 : 726528 : sum += c;
195 : 44 : return !length && !sum;
196 : : }
197 : :
198 : 11 : void __init probe_roms(void)
199 : : {
200 : 11 : const unsigned char *rom;
201 : 11 : unsigned long start, length, upper;
202 : 11 : unsigned char c;
203 : 11 : int i;
204 : :
205 : : /* video rom */
206 : 11 : upper = adapter_rom_resources[0].start;
207 [ + - ]: 11 : for (start = video_rom_resource.start; start < upper; start += 2048) {
208 : 11 : rom = isa_bus_to_virt(start);
209 [ - + ]: 11 : if (!romsignature(rom))
210 : 0 : continue;
211 : :
212 : 11 : video_rom_resource.start = start;
213 : :
214 [ - + ]: 11 : if (probe_kernel_address(rom + 2, c) != 0)
215 : 0 : continue;
216 : :
217 : : /* 0 < length <= 0x7f * 512, historically */
218 : 11 : length = c * 512;
219 : :
220 : : /* if checksum okay, trust length byte */
221 [ + - + - ]: 11 : if (length && romchecksum(rom, length))
222 : 11 : video_rom_resource.end = start + length - 1;
223 : :
224 : 11 : request_resource(&iomem_resource, &video_rom_resource);
225 : 11 : break;
226 : : }
227 : :
228 : 11 : start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
229 : 11 : if (start < upper)
230 : : start = upper;
231 : :
232 : : /* system rom */
233 : 11 : request_resource(&iomem_resource, &system_rom_resource);
234 : 11 : upper = system_rom_resource.start;
235 : :
236 : : /* check for extension rom (ignore length byte!) */
237 : 11 : rom = isa_bus_to_virt(extension_rom_resource.start);
238 [ - + ]: 11 : if (romsignature(rom)) {
239 : 0 : length = resource_size(&extension_rom_resource);
240 [ # # ]: 0 : if (romchecksum(rom, length)) {
241 : 0 : request_resource(&iomem_resource, &extension_rom_resource);
242 : 0 : upper = extension_rom_resource.start;
243 : : }
244 : : }
245 : :
246 : : /* check for adapter roms on 2k boundaries */
247 [ + + ]: 851 : for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) {
248 : 840 : rom = isa_bus_to_virt(start);
249 [ + + ]: 840 : if (!romsignature(rom))
250 : 807 : continue;
251 : :
252 [ - + ]: 33 : if (probe_kernel_address(rom + 2, c) != 0)
253 : 0 : continue;
254 : :
255 : : /* 0 < length <= 0x7f * 512, historically */
256 : 33 : length = c * 512;
257 : :
258 : : /* but accept any length that fits if checksum okay */
259 [ + - + - : 33 : if (!length || start + length > upper || !romchecksum(rom, length))
+ + ]
260 : 21 : continue;
261 : :
262 : 12 : adapter_rom_resources[i].start = start;
263 : 12 : adapter_rom_resources[i].end = start + length - 1;
264 : 12 : request_resource(&iomem_resource, &adapter_rom_resources[i]);
265 : :
266 : 12 : start = adapter_rom_resources[i++].end & ~2047UL;
267 : : }
268 : 11 : }
269 : :
|