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

cpqphp_nvram.c (13028B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Compaq Hot Plug Controller Driver
      4 *
      5 * Copyright (C) 1995,2001 Compaq Computer Corporation
      6 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
      7 * Copyright (C) 2001 IBM Corp.
      8 *
      9 * All rights reserved.
     10 *
     11 * Send feedback to <greg@kroah.com>
     12 *
     13 */
     14
     15#include <linux/module.h>
     16#include <linux/kernel.h>
     17#include <linux/types.h>
     18#include <linux/proc_fs.h>
     19#include <linux/slab.h>
     20#include <linux/workqueue.h>
     21#include <linux/pci.h>
     22#include <linux/pci_hotplug.h>
     23#include <linux/uaccess.h>
     24#include "cpqphp.h"
     25#include "cpqphp_nvram.h"
     26
     27
     28#define ROM_INT15_PHY_ADDR		0x0FF859
     29#define READ_EV				0xD8A4
     30#define WRITE_EV			0xD8A5
     31
     32struct register_foo {
     33	union {
     34		unsigned long lword;		/* eax */
     35		unsigned short word;		/* ax */
     36
     37		struct {
     38			unsigned char low;	/* al */
     39			unsigned char high;	/* ah */
     40		} byte;
     41	} data;
     42
     43	unsigned char opcode;	/* see below */
     44	unsigned long length;	/* if the reg. is a pointer, how much data */
     45} __attribute__ ((packed));
     46
     47struct all_reg {
     48	struct register_foo eax_reg;
     49	struct register_foo ebx_reg;
     50	struct register_foo ecx_reg;
     51	struct register_foo edx_reg;
     52	struct register_foo edi_reg;
     53	struct register_foo esi_reg;
     54	struct register_foo eflags_reg;
     55} __attribute__ ((packed));
     56
     57
     58struct ev_hrt_header {
     59	u8 Version;
     60	u8 num_of_ctrl;
     61	u8 next;
     62};
     63
     64struct ev_hrt_ctrl {
     65	u8 bus;
     66	u8 device;
     67	u8 function;
     68	u8 mem_avail;
     69	u8 p_mem_avail;
     70	u8 io_avail;
     71	u8 bus_avail;
     72	u8 next;
     73};
     74
     75
     76static u8 evbuffer_init;
     77static u8 evbuffer_length;
     78static u8 evbuffer[1024];
     79
     80static void __iomem *compaq_int15_entry_point;
     81
     82/* lock for ordering int15_bios_call() */
     83static DEFINE_SPINLOCK(int15_lock);
     84
     85
     86/* This is a series of function that deals with
     87 * setting & getting the hotplug resource table in some environment variable.
     88 */
     89
     90/*
     91 * We really shouldn't be doing this unless there is a _very_ good reason to!!!
     92 * greg k-h
     93 */
     94
     95
     96static u32 add_byte(u32 **p_buffer, u8 value, u32 *used, u32 *avail)
     97{
     98	u8 **tByte;
     99
    100	if ((*used + 1) > *avail)
    101		return(1);
    102
    103	*((u8 *)*p_buffer) = value;
    104	tByte = (u8 **)p_buffer;
    105	(*tByte)++;
    106	*used += 1;
    107	return(0);
    108}
    109
    110
    111static u32 add_dword(u32 **p_buffer, u32 value, u32 *used, u32 *avail)
    112{
    113	if ((*used + 4) > *avail)
    114		return(1);
    115
    116	**p_buffer = value;
    117	(*p_buffer)++;
    118	*used += 4;
    119	return(0);
    120}
    121
    122
    123/*
    124 * check_for_compaq_ROM
    125 *
    126 * this routine verifies that the ROM OEM string is 'COMPAQ'
    127 *
    128 * returns 0 for non-Compaq ROM, 1 for Compaq ROM
    129 */
    130static int check_for_compaq_ROM(void __iomem *rom_start)
    131{
    132	u8 temp1, temp2, temp3, temp4, temp5, temp6;
    133	int result = 0;
    134
    135	temp1 = readb(rom_start + 0xffea + 0);
    136	temp2 = readb(rom_start + 0xffea + 1);
    137	temp3 = readb(rom_start + 0xffea + 2);
    138	temp4 = readb(rom_start + 0xffea + 3);
    139	temp5 = readb(rom_start + 0xffea + 4);
    140	temp6 = readb(rom_start + 0xffea + 5);
    141	if ((temp1 == 'C') &&
    142	    (temp2 == 'O') &&
    143	    (temp3 == 'M') &&
    144	    (temp4 == 'P') &&
    145	    (temp5 == 'A') &&
    146	    (temp6 == 'Q')) {
    147		result = 1;
    148	}
    149	dbg("%s - returned %d\n", __func__, result);
    150	return result;
    151}
    152
    153
    154static u32 access_EV(u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
    155{
    156	unsigned long flags;
    157	int op = operation;
    158	int ret_val;
    159
    160	if (!compaq_int15_entry_point)
    161		return -ENODEV;
    162
    163	spin_lock_irqsave(&int15_lock, flags);
    164	__asm__ (
    165		"xorl   %%ebx,%%ebx\n" \
    166		"xorl    %%edx,%%edx\n" \
    167		"pushf\n" \
    168		"push %%cs\n" \
    169		"cli\n" \
    170		"call *%6\n"
    171		: "=c" (*buf_size), "=a" (ret_val)
    172		: "a" (op), "c" (*buf_size), "S" (ev_name),
    173		"D" (buffer), "m" (compaq_int15_entry_point)
    174		: "%ebx", "%edx");
    175	spin_unlock_irqrestore(&int15_lock, flags);
    176
    177	return((ret_val & 0xFF00) >> 8);
    178}
    179
    180
    181/*
    182 * load_HRT
    183 *
    184 * Read the hot plug Resource Table from NVRAM
    185 */
    186static int load_HRT(void __iomem *rom_start)
    187{
    188	u32 available;
    189	u32 temp_dword;
    190	u8 temp_byte = 0xFF;
    191	u32 rc;
    192
    193	if (!check_for_compaq_ROM(rom_start))
    194		return -ENODEV;
    195
    196	available = 1024;
    197
    198	/* Now load the EV */
    199	temp_dword = available;
    200
    201	rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);
    202
    203	evbuffer_length = temp_dword;
    204
    205	/* We're maintaining the resource lists so write FF to invalidate old
    206	 * info
    207	 */
    208	temp_dword = 1;
    209
    210	rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);
    211
    212	return rc;
    213}
    214
    215
    216/*
    217 * store_HRT
    218 *
    219 * Save the hot plug Resource Table in NVRAM
    220 */
    221static u32 store_HRT(void __iomem *rom_start)
    222{
    223	u32 *buffer;
    224	u32 *pFill;
    225	u32 usedbytes;
    226	u32 available;
    227	u32 temp_dword;
    228	u32 rc;
    229	u8 loop;
    230	u8 numCtrl = 0;
    231	struct controller *ctrl;
    232	struct pci_resource *resNode;
    233	struct ev_hrt_header *p_EV_header;
    234	struct ev_hrt_ctrl *p_ev_ctrl;
    235
    236	available = 1024;
    237
    238	if (!check_for_compaq_ROM(rom_start))
    239		return(1);
    240
    241	buffer = (u32 *) evbuffer;
    242
    243	if (!buffer)
    244		return(1);
    245
    246	pFill = buffer;
    247	usedbytes = 0;
    248
    249	p_EV_header = (struct ev_hrt_header *) pFill;
    250
    251	ctrl = cpqhp_ctrl_list;
    252
    253	/* The revision of this structure */
    254	rc = add_byte(&pFill, 1 + ctrl->push_flag, &usedbytes, &available);
    255	if (rc)
    256		return(rc);
    257
    258	/* The number of controllers */
    259	rc = add_byte(&pFill, 1, &usedbytes, &available);
    260	if (rc)
    261		return(rc);
    262
    263	while (ctrl) {
    264		p_ev_ctrl = (struct ev_hrt_ctrl *) pFill;
    265
    266		numCtrl++;
    267
    268		/* The bus number */
    269		rc = add_byte(&pFill, ctrl->bus, &usedbytes, &available);
    270		if (rc)
    271			return(rc);
    272
    273		/* The device Number */
    274		rc = add_byte(&pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
    275		if (rc)
    276			return(rc);
    277
    278		/* The function Number */
    279		rc = add_byte(&pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
    280		if (rc)
    281			return(rc);
    282
    283		/* Skip the number of available entries */
    284		rc = add_dword(&pFill, 0, &usedbytes, &available);
    285		if (rc)
    286			return(rc);
    287
    288		/* Figure out memory Available */
    289
    290		resNode = ctrl->mem_head;
    291
    292		loop = 0;
    293
    294		while (resNode) {
    295			loop++;
    296
    297			/* base */
    298			rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
    299			if (rc)
    300				return(rc);
    301
    302			/* length */
    303			rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
    304			if (rc)
    305				return(rc);
    306
    307			resNode = resNode->next;
    308		}
    309
    310		/* Fill in the number of entries */
    311		p_ev_ctrl->mem_avail = loop;
    312
    313		/* Figure out prefetchable memory Available */
    314
    315		resNode = ctrl->p_mem_head;
    316
    317		loop = 0;
    318
    319		while (resNode) {
    320			loop++;
    321
    322			/* base */
    323			rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
    324			if (rc)
    325				return(rc);
    326
    327			/* length */
    328			rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
    329			if (rc)
    330				return(rc);
    331
    332			resNode = resNode->next;
    333		}
    334
    335		/* Fill in the number of entries */
    336		p_ev_ctrl->p_mem_avail = loop;
    337
    338		/* Figure out IO Available */
    339
    340		resNode = ctrl->io_head;
    341
    342		loop = 0;
    343
    344		while (resNode) {
    345			loop++;
    346
    347			/* base */
    348			rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
    349			if (rc)
    350				return(rc);
    351
    352			/* length */
    353			rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
    354			if (rc)
    355				return(rc);
    356
    357			resNode = resNode->next;
    358		}
    359
    360		/* Fill in the number of entries */
    361		p_ev_ctrl->io_avail = loop;
    362
    363		/* Figure out bus Available */
    364
    365		resNode = ctrl->bus_head;
    366
    367		loop = 0;
    368
    369		while (resNode) {
    370			loop++;
    371
    372			/* base */
    373			rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
    374			if (rc)
    375				return(rc);
    376
    377			/* length */
    378			rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
    379			if (rc)
    380				return(rc);
    381
    382			resNode = resNode->next;
    383		}
    384
    385		/* Fill in the number of entries */
    386		p_ev_ctrl->bus_avail = loop;
    387
    388		ctrl = ctrl->next;
    389	}
    390
    391	p_EV_header->num_of_ctrl = numCtrl;
    392
    393	/* Now store the EV */
    394
    395	temp_dword = usedbytes;
    396
    397	rc = access_EV(WRITE_EV, "CQTHPS", (u8 *) buffer, &temp_dword);
    398
    399	dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword);
    400
    401	evbuffer_length = temp_dword;
    402
    403	if (rc) {
    404		err(msg_unable_to_save);
    405		return(1);
    406	}
    407
    408	return(0);
    409}
    410
    411
    412void compaq_nvram_init(void __iomem *rom_start)
    413{
    414	if (rom_start)
    415		compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);
    416
    417	dbg("int15 entry  = %p\n", compaq_int15_entry_point);
    418}
    419
    420
    421int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl)
    422{
    423	u8 bus, device, function;
    424	u8 nummem, numpmem, numio, numbus;
    425	u32 rc;
    426	u8 *p_byte;
    427	struct pci_resource *mem_node;
    428	struct pci_resource *p_mem_node;
    429	struct pci_resource *io_node;
    430	struct pci_resource *bus_node;
    431	struct ev_hrt_ctrl *p_ev_ctrl;
    432	struct ev_hrt_header *p_EV_header;
    433
    434	if (!evbuffer_init) {
    435		/* Read the resource list information in from NVRAM */
    436		if (load_HRT(rom_start))
    437			memset(evbuffer, 0, 1024);
    438
    439		evbuffer_init = 1;
    440	}
    441
    442	/* If we saved information in NVRAM, use it now */
    443	p_EV_header = (struct ev_hrt_header *) evbuffer;
    444
    445	/* The following code is for systems where version 1.0 of this
    446	 * driver has been loaded, but doesn't support the hardware.
    447	 * In that case, the driver would incorrectly store something
    448	 * in NVRAM.
    449	 */
    450	if ((p_EV_header->Version == 2) ||
    451	    ((p_EV_header->Version == 1) && !ctrl->push_flag)) {
    452		p_byte = &(p_EV_header->next);
    453
    454		p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);
    455
    456		p_byte += 3;
    457
    458		if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
    459			return 2;
    460
    461		bus = p_ev_ctrl->bus;
    462		device = p_ev_ctrl->device;
    463		function = p_ev_ctrl->function;
    464
    465		while ((bus != ctrl->bus) ||
    466		       (device != PCI_SLOT(ctrl->pci_dev->devfn)) ||
    467		       (function != PCI_FUNC(ctrl->pci_dev->devfn))) {
    468			nummem = p_ev_ctrl->mem_avail;
    469			numpmem = p_ev_ctrl->p_mem_avail;
    470			numio = p_ev_ctrl->io_avail;
    471			numbus = p_ev_ctrl->bus_avail;
    472
    473			p_byte += 4;
    474
    475			if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
    476				return 2;
    477
    478			/* Skip forward to the next entry */
    479			p_byte += (nummem + numpmem + numio + numbus) * 8;
    480
    481			if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
    482				return 2;
    483
    484			p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;
    485
    486			p_byte += 3;
    487
    488			if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
    489				return 2;
    490
    491			bus = p_ev_ctrl->bus;
    492			device = p_ev_ctrl->device;
    493			function = p_ev_ctrl->function;
    494		}
    495
    496		nummem = p_ev_ctrl->mem_avail;
    497		numpmem = p_ev_ctrl->p_mem_avail;
    498		numio = p_ev_ctrl->io_avail;
    499		numbus = p_ev_ctrl->bus_avail;
    500
    501		p_byte += 4;
    502
    503		if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
    504			return 2;
    505
    506		while (nummem--) {
    507			mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
    508
    509			if (!mem_node)
    510				break;
    511
    512			mem_node->base = *(u32 *)p_byte;
    513			dbg("mem base = %8.8x\n", mem_node->base);
    514			p_byte += 4;
    515
    516			if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    517				kfree(mem_node);
    518				return 2;
    519			}
    520
    521			mem_node->length = *(u32 *)p_byte;
    522			dbg("mem length = %8.8x\n", mem_node->length);
    523			p_byte += 4;
    524
    525			if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    526				kfree(mem_node);
    527				return 2;
    528			}
    529
    530			mem_node->next = ctrl->mem_head;
    531			ctrl->mem_head = mem_node;
    532		}
    533
    534		while (numpmem--) {
    535			p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
    536
    537			if (!p_mem_node)
    538				break;
    539
    540			p_mem_node->base = *(u32 *)p_byte;
    541			dbg("pre-mem base = %8.8x\n", p_mem_node->base);
    542			p_byte += 4;
    543
    544			if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    545				kfree(p_mem_node);
    546				return 2;
    547			}
    548
    549			p_mem_node->length = *(u32 *)p_byte;
    550			dbg("pre-mem length = %8.8x\n", p_mem_node->length);
    551			p_byte += 4;
    552
    553			if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    554				kfree(p_mem_node);
    555				return 2;
    556			}
    557
    558			p_mem_node->next = ctrl->p_mem_head;
    559			ctrl->p_mem_head = p_mem_node;
    560		}
    561
    562		while (numio--) {
    563			io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
    564
    565			if (!io_node)
    566				break;
    567
    568			io_node->base = *(u32 *)p_byte;
    569			dbg("io base = %8.8x\n", io_node->base);
    570			p_byte += 4;
    571
    572			if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    573				kfree(io_node);
    574				return 2;
    575			}
    576
    577			io_node->length = *(u32 *)p_byte;
    578			dbg("io length = %8.8x\n", io_node->length);
    579			p_byte += 4;
    580
    581			if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    582				kfree(io_node);
    583				return 2;
    584			}
    585
    586			io_node->next = ctrl->io_head;
    587			ctrl->io_head = io_node;
    588		}
    589
    590		while (numbus--) {
    591			bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
    592
    593			if (!bus_node)
    594				break;
    595
    596			bus_node->base = *(u32 *)p_byte;
    597			p_byte += 4;
    598
    599			if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    600				kfree(bus_node);
    601				return 2;
    602			}
    603
    604			bus_node->length = *(u32 *)p_byte;
    605			p_byte += 4;
    606
    607			if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    608				kfree(bus_node);
    609				return 2;
    610			}
    611
    612			bus_node->next = ctrl->bus_head;
    613			ctrl->bus_head = bus_node;
    614		}
    615
    616		/* If all of the following fail, we don't have any resources for
    617		 * hot plug add
    618		 */
    619		rc = 1;
    620		rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
    621		rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
    622		rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
    623		rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
    624
    625		if (rc)
    626			return(rc);
    627	} else {
    628		if ((evbuffer[0] != 0) && (!ctrl->push_flag))
    629			return 1;
    630	}
    631
    632	return 0;
    633}
    634
    635
    636int compaq_nvram_store(void __iomem *rom_start)
    637{
    638	int rc = 1;
    639
    640	if (rom_start == NULL)
    641		return -ENODEV;
    642
    643	if (evbuffer_init) {
    644		rc = store_HRT(rom_start);
    645		if (rc)
    646			err(msg_unable_to_save);
    647	}
    648	return rc;
    649}
    650