probe_roms.c 6.3 KB

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