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

nfp_hwinfo.c (6851B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
      2/* Copyright (C) 2015-2017 Netronome Systems, Inc. */
      3
      4/* Parse the hwinfo table that the ARM firmware builds in the ARM scratch SRAM
      5 * after chip reset.
      6 *
      7 * Examples of the fields:
      8 *   me.count = 40
      9 *   me.mask = 0x7f_ffff_ffff
     10 *
     11 *   me.count is the total number of MEs on the system.
     12 *   me.mask is the bitmask of MEs that are available for application usage.
     13 *
     14 *   (ie, in this example, ME 39 has been reserved by boardconfig.)
     15 */
     16
     17#include <asm/byteorder.h>
     18#include <asm/unaligned.h>
     19#include <linux/delay.h>
     20#include <linux/log2.h>
     21#include <linux/kernel.h>
     22#include <linux/module.h>
     23#include <linux/slab.h>
     24
     25#define NFP_SUBSYS "nfp_hwinfo"
     26
     27#include "crc32.h"
     28#include "nfp.h"
     29#include "nfp_cpp.h"
     30#include "nfp6000/nfp6000.h"
     31
     32#define HWINFO_SIZE_MIN	0x100
     33#define HWINFO_WAIT	20	/* seconds */
     34
     35/* The Hardware Info Table defines the properties of the system.
     36 *
     37 * HWInfo v1 Table (fixed size)
     38 *
     39 * 0x0000: u32 version	        Hardware Info Table version (1.0)
     40 * 0x0004: u32 size	        Total size of the table, including
     41 *			        the CRC32 (IEEE 802.3)
     42 * 0x0008: u32 jumptab	        Offset of key/value table
     43 * 0x000c: u32 keys	        Total number of keys in the key/value table
     44 * NNNNNN:		        Key/value jump table and string data
     45 * (size - 4): u32 crc32	CRC32 (same as IEEE 802.3, POSIX csum, etc)
     46 *				CRC32("",0) = ~0, CRC32("a",1) = 0x48C279FE
     47 *
     48 * HWInfo v2 Table (variable size)
     49 *
     50 * 0x0000: u32 version	        Hardware Info Table version (2.0)
     51 * 0x0004: u32 size	        Current size of the data area, excluding CRC32
     52 * 0x0008: u32 limit	        Maximum size of the table
     53 * 0x000c: u32 reserved	        Unused, set to zero
     54 * NNNNNN:			Key/value data
     55 * (size - 4): u32 crc32	CRC32 (same as IEEE 802.3, POSIX csum, etc)
     56 *				CRC32("",0) = ~0, CRC32("a",1) = 0x48C279FE
     57 *
     58 * If the HWInfo table is in the process of being updated, the low bit
     59 * of version will be set.
     60 *
     61 * HWInfo v1 Key/Value Table
     62 * -------------------------
     63 *
     64 *  The key/value table is a set of offsets to ASCIIZ strings which have
     65 *  been strcmp(3) sorted (yes, please use bsearch(3) on the table).
     66 *
     67 *  All keys are guaranteed to be unique.
     68 *
     69 * N+0:	u32 key_1		Offset to the first key
     70 * N+4:	u32 val_1		Offset to the first value
     71 * N+8: u32 key_2		Offset to the second key
     72 * N+c: u32 val_2		Offset to the second value
     73 * ...
     74 *
     75 * HWInfo v2 Key/Value Table
     76 * -------------------------
     77 *
     78 * Packed UTF8Z strings, ie 'key1\000value1\000key2\000value2\000'
     79 *
     80 * Unsorted.
     81 */
     82
     83#define NFP_HWINFO_VERSION_1 ('H' << 24 | 'I' << 16 | 1 << 8 | 0 << 1 | 0)
     84#define NFP_HWINFO_VERSION_2 ('H' << 24 | 'I' << 16 | 2 << 8 | 0 << 1 | 0)
     85#define NFP_HWINFO_VERSION_UPDATING	BIT(0)
     86
     87struct nfp_hwinfo {
     88	u8 start[0];
     89
     90	__le32 version;
     91	__le32 size;
     92
     93	/* v2 specific fields */
     94	__le32 limit;
     95	__le32 resv;
     96
     97	char data[];
     98};
     99
    100static bool nfp_hwinfo_is_updating(struct nfp_hwinfo *hwinfo)
    101{
    102	return le32_to_cpu(hwinfo->version) & NFP_HWINFO_VERSION_UPDATING;
    103}
    104
    105static int
    106hwinfo_db_walk(struct nfp_cpp *cpp, struct nfp_hwinfo *hwinfo, u32 size)
    107{
    108	const char *key, *val, *end = hwinfo->data + size;
    109
    110	for (key = hwinfo->data; *key && key < end;
    111	     key = val + strlen(val) + 1) {
    112
    113		val = key + strlen(key) + 1;
    114		if (val >= end) {
    115			nfp_warn(cpp, "Bad HWINFO - overflowing key\n");
    116			return -EINVAL;
    117		}
    118
    119		if (val + strlen(val) + 1 > end) {
    120			nfp_warn(cpp, "Bad HWINFO - overflowing value\n");
    121			return -EINVAL;
    122		}
    123	}
    124
    125	return 0;
    126}
    127
    128static int
    129hwinfo_db_validate(struct nfp_cpp *cpp, struct nfp_hwinfo *db, u32 len)
    130{
    131	u32 size, crc;
    132
    133	size = le32_to_cpu(db->size);
    134	if (size > len) {
    135		nfp_err(cpp, "Unsupported hwinfo size %u > %u\n", size, len);
    136		return -EINVAL;
    137	}
    138
    139	size -= sizeof(u32);
    140	crc = crc32_posix(db, size);
    141	if (crc != get_unaligned_le32(db->start + size)) {
    142		nfp_err(cpp, "Corrupt hwinfo table (CRC mismatch), calculated 0x%x, expected 0x%x\n",
    143			crc, get_unaligned_le32(db->start + size));
    144
    145		return -EINVAL;
    146	}
    147
    148	return hwinfo_db_walk(cpp, db, size);
    149}
    150
    151static struct nfp_hwinfo *
    152hwinfo_try_fetch(struct nfp_cpp *cpp, size_t *cpp_size)
    153{
    154	struct nfp_hwinfo *header;
    155	struct nfp_resource *res;
    156	u64 cpp_addr;
    157	u32 cpp_id;
    158	int err;
    159	u8 *db;
    160
    161	res = nfp_resource_acquire(cpp, NFP_RESOURCE_NFP_HWINFO);
    162	if (!IS_ERR(res)) {
    163		cpp_id = nfp_resource_cpp_id(res);
    164		cpp_addr = nfp_resource_address(res);
    165		*cpp_size = nfp_resource_size(res);
    166
    167		nfp_resource_release(res);
    168
    169		if (*cpp_size < HWINFO_SIZE_MIN)
    170			return NULL;
    171	} else if (PTR_ERR(res) == -ENOENT) {
    172		/* Try getting the HWInfo table from the 'classic' location */
    173		cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU,
    174					   NFP_CPP_ACTION_RW, 0, 1);
    175		cpp_addr = 0x30000;
    176		*cpp_size = 0x0e000;
    177	} else {
    178		return NULL;
    179	}
    180
    181	db = kmalloc(*cpp_size + 1, GFP_KERNEL);
    182	if (!db)
    183		return NULL;
    184
    185	err = nfp_cpp_read(cpp, cpp_id, cpp_addr, db, *cpp_size);
    186	if (err != *cpp_size)
    187		goto exit_free;
    188
    189	header = (void *)db;
    190	if (nfp_hwinfo_is_updating(header))
    191		goto exit_free;
    192
    193	if (le32_to_cpu(header->version) != NFP_HWINFO_VERSION_2) {
    194		nfp_err(cpp, "Unknown HWInfo version: 0x%08x\n",
    195			le32_to_cpu(header->version));
    196		goto exit_free;
    197	}
    198
    199	/* NULL-terminate for safety */
    200	db[*cpp_size] = '\0';
    201
    202	return (void *)db;
    203exit_free:
    204	kfree(db);
    205	return NULL;
    206}
    207
    208static struct nfp_hwinfo *hwinfo_fetch(struct nfp_cpp *cpp, size_t *hwdb_size)
    209{
    210	const unsigned long wait_until = jiffies + HWINFO_WAIT * HZ;
    211	struct nfp_hwinfo *db;
    212	int err;
    213
    214	for (;;) {
    215		const unsigned long start_time = jiffies;
    216
    217		db = hwinfo_try_fetch(cpp, hwdb_size);
    218		if (db)
    219			return db;
    220
    221		err = msleep_interruptible(100);
    222		if (err || time_after(start_time, wait_until)) {
    223			nfp_err(cpp, "NFP access error\n");
    224			return NULL;
    225		}
    226	}
    227}
    228
    229struct nfp_hwinfo *nfp_hwinfo_read(struct nfp_cpp *cpp)
    230{
    231	struct nfp_hwinfo *db;
    232	size_t hwdb_size = 0;
    233	int err;
    234
    235	db = hwinfo_fetch(cpp, &hwdb_size);
    236	if (!db)
    237		return NULL;
    238
    239	err = hwinfo_db_validate(cpp, db, hwdb_size);
    240	if (err) {
    241		kfree(db);
    242		return NULL;
    243	}
    244
    245	return db;
    246}
    247
    248/**
    249 * nfp_hwinfo_lookup() - Find a value in the HWInfo table by name
    250 * @hwinfo:	NFP HWinfo table
    251 * @lookup:	HWInfo name to search for
    252 *
    253 * Return: Value of the HWInfo name, or NULL
    254 */
    255const char *nfp_hwinfo_lookup(struct nfp_hwinfo *hwinfo, const char *lookup)
    256{
    257	const char *key, *val, *end;
    258
    259	if (!hwinfo || !lookup)
    260		return NULL;
    261
    262	end = hwinfo->data + le32_to_cpu(hwinfo->size) - sizeof(u32);
    263
    264	for (key = hwinfo->data; *key && key < end;
    265	     key = val + strlen(val) + 1) {
    266
    267		val = key + strlen(key) + 1;
    268
    269		if (strcmp(key, lookup) == 0)
    270			return val;
    271	}
    272
    273	return NULL;
    274}
    275
    276char *nfp_hwinfo_get_packed_strings(struct nfp_hwinfo *hwinfo)
    277{
    278	return hwinfo->data;
    279}
    280
    281u32 nfp_hwinfo_get_packed_str_size(struct nfp_hwinfo *hwinfo)
    282{
    283	return le32_to_cpu(hwinfo->size) - sizeof(u32);
    284}