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