LCOV - code coverage report
Current view: top level - arch/x86/kernel - probe_roms.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 25 98 25.5 %
Date: 2021-04-22 12:43:58 Functions: 2 9 22.2 %

          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             : 

Generated by: LCOV version 1.14