cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

probe_roms.c (6861B)


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