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