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 static bool match_id(struct pci_dev *pdev, unsigned short vendor, unsigned short device) 82 { 83 struct pci_driver *drv = pdev->driver; 84 const struct pci_device_id *id; 85 86 if (pdev->vendor == vendor && pdev->device == device) 87 return true; 88 89 for (id = drv ? drv->id_table : NULL; id && id->vendor; id++) 90 if (id->vendor == vendor && id->device == device) 91 break; 92 93 return id && id->vendor; 94 } 95 96 static bool probe_list(struct pci_dev *pdev, unsigned short vendor, 97 const unsigned char *rom_list) 98 { 99 unsigned short device; 100 101 do { 102 if (probe_kernel_address(rom_list, device) != 0) 103 device = 0; 104 105 if (device && match_id(pdev, vendor, device)) 106 break; 107 108 rom_list += 2; 109 } while (device); 110 111 return !!device; 112 } 113 114 static struct resource *find_oprom(struct pci_dev *pdev) 115 { 116 struct resource *oprom = NULL; 117 int i; 118 119 for (i = 0; i < ARRAY_SIZE(adapter_rom_resources); i++) { 120 struct resource *res = &adapter_rom_resources[i]; 121 unsigned short offset, vendor, device, list, rev; 122 const unsigned char *rom; 123 124 if (res->end == 0) 125 break; 126 127 rom = isa_bus_to_virt(res->start); 128 if (probe_kernel_address(rom + 0x18, offset) != 0) 129 continue; 130 131 if (probe_kernel_address(rom + offset + 0x4, vendor) != 0) 132 continue; 133 134 if (probe_kernel_address(rom + offset + 0x6, device) != 0) 135 continue; 136 137 if (match_id(pdev, vendor, device)) { 138 oprom = res; 139 break; 140 } 141 142 if (probe_kernel_address(rom + offset + 0x8, list) == 0 && 143 probe_kernel_address(rom + offset + 0xc, rev) == 0 && 144 rev >= 3 && list && 145 probe_list(pdev, vendor, rom + offset + list)) { 146 oprom = res; 147 break; 148 } 149 } 150 151 return oprom; 152 } 153 154 void __iomem *pci_map_biosrom(struct pci_dev *pdev) 155 { 156 struct resource *oprom = find_oprom(pdev); 157 158 if (!oprom) 159 return NULL; 160 161 return ioremap(oprom->start, resource_size(oprom)); 162 } 163 EXPORT_SYMBOL(pci_map_biosrom); 164 165 void pci_unmap_biosrom(void __iomem *image) 166 { 167 iounmap(image); 168 } 169 EXPORT_SYMBOL(pci_unmap_biosrom); 170 171 size_t pci_biosrom_size(struct pci_dev *pdev) 172 { 173 struct resource *oprom = find_oprom(pdev); 174 175 return oprom ? resource_size(oprom) : 0; 176 } 177 EXPORT_SYMBOL(pci_biosrom_size); 178 179 #define ROMSIGNATURE 0xaa55 180 181 static int __init romsignature(const unsigned char *rom) 182 { 183 const unsigned short * const ptr = (const unsigned short *)rom; 184 unsigned short sig; 185 186 return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE; 187 } 188 189 static int __init romchecksum(const unsigned char *rom, unsigned long length) 190 { 191 unsigned char sum, c; 192 193 for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--) 194 sum += c; 195 return !length && !sum; 196 } 197 198 void __init probe_roms(void) 199 { 200 const unsigned char *rom; 201 unsigned long start, length, upper; 202 unsigned char c; 203 int i; 204 205 /* video rom */ 206 upper = adapter_rom_resources[0].start; 207 for (start = video_rom_resource.start; start < upper; start += 2048) { 208 rom = isa_bus_to_virt(start); 209 if (!romsignature(rom)) 210 continue; 211 212 video_rom_resource.start = start; 213 214 if (probe_kernel_address(rom + 2, c) != 0) 215 continue; 216 217 /* 0 < length <= 0x7f * 512, historically */ 218 length = c * 512; 219 220 /* if checksum okay, trust length byte */ 221 if (length && romchecksum(rom, length)) 222 video_rom_resource.end = start + length - 1; 223 224 request_resource(&iomem_resource, &video_rom_resource); 225 break; 226 } 227 228 start = (video_rom_resource.end + 1 + 2047) & ~2047UL; 229 if (start < upper) 230 start = upper; 231 232 /* system rom */ 233 request_resource(&iomem_resource, &system_rom_resource); 234 upper = system_rom_resource.start; 235 236 /* check for extension rom (ignore length byte!) */ 237 rom = isa_bus_to_virt(extension_rom_resource.start); 238 if (romsignature(rom)) { 239 length = resource_size(&extension_rom_resource); 240 if (romchecksum(rom, length)) { 241 request_resource(&iomem_resource, &extension_rom_resource); 242 upper = extension_rom_resource.start; 243 } 244 } 245 246 /* check for adapter roms on 2k boundaries */ 247 for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) { 248 rom = isa_bus_to_virt(start); 249 if (!romsignature(rom)) 250 continue; 251 252 if (probe_kernel_address(rom + 2, c) != 0) 253 continue; 254 255 /* 0 < length <= 0x7f * 512, historically */ 256 length = c * 512; 257 258 /* but accept any length that fits if checksum okay */ 259 if (!length || start + length > upper || !romchecksum(rom, length)) 260 continue; 261 262 adapter_rom_resources[i].start = start; 263 adapter_rom_resources[i].end = start + length - 1; 264 request_resource(&iomem_resource, &adapter_rom_resources[i]); 265 266 start = adapter_rom_resources[i++].end & ~2047UL; 267 } 268 } 269 270