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 void *rom_list)
98 : {
99 0 : unsigned short device;
100 :
101 0 : do {
102 0 : if (get_kernel_nofault(device, rom_list) != 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 void *rom;
123 :
124 0 : if (res->end == 0)
125 : break;
126 :
127 0 : rom = isa_bus_to_virt(res->start);
128 0 : if (get_kernel_nofault(offset, rom + 0x18) != 0)
129 0 : continue;
130 :
131 0 : if (get_kernel_nofault(vendor, rom + offset + 0x4) != 0)
132 0 : continue;
133 :
134 0 : if (get_kernel_nofault(device, rom + offset + 0x6) != 0)
135 0 : continue;
136 :
137 0 : if (match_id(pdev, vendor, device)) {
138 : oprom = res;
139 : break;
140 : }
141 :
142 0 : if (get_kernel_nofault(list, rom + offset + 0x8) == 0 &&
143 0 : get_kernel_nofault(rev, rom + offset + 0xc) == 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 97 : static int __init romsignature(const unsigned char *rom)
182 : {
183 97 : const unsigned short * const ptr = (const unsigned short *)rom;
184 97 : unsigned short sig;
185 :
186 97 : return get_kernel_nofault(sig, ptr) == 0 && sig == ROMSIGNATURE;
187 : }
188 :
189 0 : static int __init romchecksum(const unsigned char *rom, unsigned long length)
190 : {
191 0 : unsigned char sum, c;
192 :
193 0 : for (sum = 0; length && get_kernel_nofault(c, rom++) == 0; length--)
194 0 : sum += c;
195 0 : return !length && !sum;
196 : }
197 :
198 1 : void __init probe_roms(void)
199 : {
200 1 : const unsigned char *rom;
201 1 : unsigned long start, length, upper;
202 1 : unsigned char c;
203 1 : int i;
204 :
205 : /* video rom */
206 1 : upper = adapter_rom_resources[0].start;
207 17 : for (start = video_rom_resource.start; start < upper; start += 2048) {
208 16 : rom = isa_bus_to_virt(start);
209 16 : if (!romsignature(rom))
210 16 : continue;
211 :
212 0 : video_rom_resource.start = start;
213 :
214 0 : if (get_kernel_nofault(c, rom + 2) != 0)
215 0 : continue;
216 :
217 : /* 0 < length <= 0x7f * 512, historically */
218 0 : length = c * 512;
219 :
220 : /* if checksum okay, trust length byte */
221 0 : if (length && romchecksum(rom, length))
222 0 : video_rom_resource.end = start + length - 1;
223 :
224 0 : request_resource(&iomem_resource, &video_rom_resource);
225 0 : break;
226 : }
227 :
228 1 : start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
229 1 : if (start < upper)
230 : start = upper;
231 :
232 : /* system rom */
233 1 : request_resource(&iomem_resource, &system_rom_resource);
234 1 : upper = system_rom_resource.start;
235 :
236 : /* check for extension rom (ignore length byte!) */
237 1 : rom = isa_bus_to_virt(extension_rom_resource.start);
238 1 : 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 81 : for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) {
248 80 : rom = isa_bus_to_virt(start);
249 80 : if (!romsignature(rom))
250 80 : continue;
251 :
252 0 : if (get_kernel_nofault(c, rom + 2) != 0)
253 0 : continue;
254 :
255 : /* 0 < length <= 0x7f * 512, historically */
256 0 : length = c * 512;
257 :
258 : /* but accept any length that fits if checksum okay */
259 0 : if (!length || start + length > upper || !romchecksum(rom, length))
260 0 : continue;
261 :
262 0 : adapter_rom_resources[i].start = start;
263 0 : adapter_rom_resources[i].end = start + length - 1;
264 0 : request_resource(&iomem_resource, &adapter_rom_resources[i]);
265 :
266 0 : start = adapter_rom_resources[i++].end & ~2047UL;
267 : }
268 1 : }
269 :
|