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_rtsym.c (13250B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
      2/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
      3
      4/*
      5 * nfp_rtsym.c
      6 * Interface for accessing run-time symbol table
      7 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
      8 *          Jason McMullan <jason.mcmullan@netronome.com>
      9 *          Espen Skoglund <espen.skoglund@netronome.com>
     10 *          Francois H. Theron <francois.theron@netronome.com>
     11 */
     12
     13#include <asm/unaligned.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/slab.h>
     17#include <linux/io-64-nonatomic-hi-lo.h>
     18
     19#include "nfp.h"
     20#include "nfp_cpp.h"
     21#include "nfp_nffw.h"
     22#include "nfp6000/nfp6000.h"
     23
     24/* These need to match the linker */
     25#define SYM_TGT_LMEM		0
     26#define SYM_TGT_EMU_CACHE	0x17
     27
     28struct nfp_rtsym_entry {
     29	u8	type;
     30	u8	target;
     31	u8	island;
     32	u8	addr_hi;
     33	__le32	addr_lo;
     34	__le16	name;
     35	u8	menum;
     36	u8	size_hi;
     37	__le32	size_lo;
     38};
     39
     40struct nfp_rtsym_table {
     41	struct nfp_cpp *cpp;
     42	int num;
     43	char *strtab;
     44	struct nfp_rtsym symtab[];
     45};
     46
     47static int nfp_meid(u8 island_id, u8 menum)
     48{
     49	return (island_id & 0x3F) == island_id && menum < 12 ?
     50		(island_id << 4) | (menum + 4) : -1;
     51}
     52
     53static void
     54nfp_rtsym_sw_entry_init(struct nfp_rtsym_table *cache, u32 strtab_size,
     55			struct nfp_rtsym *sw, struct nfp_rtsym_entry *fw)
     56{
     57	sw->type = fw->type;
     58	sw->name = cache->strtab + le16_to_cpu(fw->name) % strtab_size;
     59	sw->addr = ((u64)fw->addr_hi << 32) | le32_to_cpu(fw->addr_lo);
     60	sw->size = ((u64)fw->size_hi << 32) | le32_to_cpu(fw->size_lo);
     61
     62	switch (fw->target) {
     63	case SYM_TGT_LMEM:
     64		sw->target = NFP_RTSYM_TARGET_LMEM;
     65		break;
     66	case SYM_TGT_EMU_CACHE:
     67		sw->target = NFP_RTSYM_TARGET_EMU_CACHE;
     68		break;
     69	default:
     70		sw->target = fw->target;
     71		break;
     72	}
     73
     74	if (fw->menum != 0xff)
     75		sw->domain = nfp_meid(fw->island, fw->menum);
     76	else if (fw->island != 0xff)
     77		sw->domain = fw->island;
     78	else
     79		sw->domain = -1;
     80}
     81
     82struct nfp_rtsym_table *nfp_rtsym_table_read(struct nfp_cpp *cpp)
     83{
     84	struct nfp_rtsym_table *rtbl;
     85	const struct nfp_mip *mip;
     86
     87	mip = nfp_mip_open(cpp);
     88	rtbl = __nfp_rtsym_table_read(cpp, mip);
     89	nfp_mip_close(mip);
     90
     91	return rtbl;
     92}
     93
     94struct nfp_rtsym_table *
     95__nfp_rtsym_table_read(struct nfp_cpp *cpp, const struct nfp_mip *mip)
     96{
     97	const u32 dram = NFP_CPP_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0) |
     98		NFP_ISL_EMEM0;
     99	u32 strtab_addr, symtab_addr, strtab_size, symtab_size;
    100	struct nfp_rtsym_entry *rtsymtab;
    101	struct nfp_rtsym_table *cache;
    102	int err, n, size;
    103
    104	if (!mip)
    105		return NULL;
    106
    107	nfp_mip_strtab(mip, &strtab_addr, &strtab_size);
    108	nfp_mip_symtab(mip, &symtab_addr, &symtab_size);
    109
    110	if (!symtab_size || !strtab_size || symtab_size % sizeof(*rtsymtab))
    111		return NULL;
    112
    113	/* Align to 64 bits */
    114	symtab_size = round_up(symtab_size, 8);
    115	strtab_size = round_up(strtab_size, 8);
    116
    117	rtsymtab = kmalloc(symtab_size, GFP_KERNEL);
    118	if (!rtsymtab)
    119		return NULL;
    120
    121	size = sizeof(*cache);
    122	size += symtab_size / sizeof(*rtsymtab) * sizeof(struct nfp_rtsym);
    123	size +=	strtab_size + 1;
    124	cache = kmalloc(size, GFP_KERNEL);
    125	if (!cache)
    126		goto exit_free_rtsym_raw;
    127
    128	cache->cpp = cpp;
    129	cache->num = symtab_size / sizeof(*rtsymtab);
    130	cache->strtab = (void *)&cache->symtab[cache->num];
    131
    132	err = nfp_cpp_read(cpp, dram, symtab_addr, rtsymtab, symtab_size);
    133	if (err != symtab_size)
    134		goto exit_free_cache;
    135
    136	err = nfp_cpp_read(cpp, dram, strtab_addr, cache->strtab, strtab_size);
    137	if (err != strtab_size)
    138		goto exit_free_cache;
    139	cache->strtab[strtab_size] = '\0';
    140
    141	for (n = 0; n < cache->num; n++)
    142		nfp_rtsym_sw_entry_init(cache, strtab_size,
    143					&cache->symtab[n], &rtsymtab[n]);
    144
    145	kfree(rtsymtab);
    146
    147	return cache;
    148
    149exit_free_cache:
    150	kfree(cache);
    151exit_free_rtsym_raw:
    152	kfree(rtsymtab);
    153	return NULL;
    154}
    155
    156/**
    157 * nfp_rtsym_count() - Get the number of RTSYM descriptors
    158 * @rtbl:	NFP RTsym table
    159 *
    160 * Return: Number of RTSYM descriptors
    161 */
    162int nfp_rtsym_count(struct nfp_rtsym_table *rtbl)
    163{
    164	if (!rtbl)
    165		return -EINVAL;
    166	return rtbl->num;
    167}
    168
    169/**
    170 * nfp_rtsym_get() - Get the Nth RTSYM descriptor
    171 * @rtbl:	NFP RTsym table
    172 * @idx:	Index (0-based) of the RTSYM descriptor
    173 *
    174 * Return: const pointer to a struct nfp_rtsym descriptor, or NULL
    175 */
    176const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx)
    177{
    178	if (!rtbl)
    179		return NULL;
    180	if (idx >= rtbl->num)
    181		return NULL;
    182
    183	return &rtbl->symtab[idx];
    184}
    185
    186/**
    187 * nfp_rtsym_lookup() - Return the RTSYM descriptor for a symbol name
    188 * @rtbl:	NFP RTsym table
    189 * @name:	Symbol name
    190 *
    191 * Return: const pointer to a struct nfp_rtsym descriptor, or NULL
    192 */
    193const struct nfp_rtsym *
    194nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name)
    195{
    196	int n;
    197
    198	if (!rtbl)
    199		return NULL;
    200
    201	for (n = 0; n < rtbl->num; n++)
    202		if (strcmp(name, rtbl->symtab[n].name) == 0)
    203			return &rtbl->symtab[n];
    204
    205	return NULL;
    206}
    207
    208u64 nfp_rtsym_size(const struct nfp_rtsym *sym)
    209{
    210	switch (sym->type) {
    211	case NFP_RTSYM_TYPE_NONE:
    212		pr_err("rtsym '%s': type NONE\n", sym->name);
    213		return 0;
    214	default:
    215		pr_warn("rtsym '%s': unknown type: %d\n", sym->name, sym->type);
    216		fallthrough;
    217	case NFP_RTSYM_TYPE_OBJECT:
    218	case NFP_RTSYM_TYPE_FUNCTION:
    219		return sym->size;
    220	case NFP_RTSYM_TYPE_ABS:
    221		return sizeof(u64);
    222	}
    223}
    224
    225static int
    226nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
    227		  u8 action, u8 token, u64 off, u32 *cpp_id, u64 *addr)
    228{
    229	if (sym->type != NFP_RTSYM_TYPE_OBJECT) {
    230		nfp_err(cpp, "rtsym '%s': direct access to non-object rtsym\n",
    231			sym->name);
    232		return -EINVAL;
    233	}
    234
    235	*addr = sym->addr + off;
    236
    237	if (sym->target == NFP_RTSYM_TARGET_EMU_CACHE) {
    238		int locality_off = nfp_cpp_mu_locality_lsb(cpp);
    239
    240		*addr &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off);
    241		*addr |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off;
    242
    243		*cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, action, token,
    244					    sym->domain);
    245	} else if (sym->target < 0) {
    246		nfp_err(cpp, "rtsym '%s': unhandled target encoding: %d\n",
    247			sym->name, sym->target);
    248		return -EINVAL;
    249	} else {
    250		*cpp_id = NFP_CPP_ISLAND_ID(sym->target, action, token,
    251					    sym->domain);
    252	}
    253
    254	return 0;
    255}
    256
    257int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
    258		     u8 action, u8 token, u64 off, void *buf, size_t len)
    259{
    260	u64 sym_size = nfp_rtsym_size(sym);
    261	u32 cpp_id;
    262	u64 addr;
    263	int err;
    264
    265	if (off > sym_size) {
    266		nfp_err(cpp, "rtsym '%s': read out of bounds: off: %lld + len: %zd > size: %lld\n",
    267			sym->name, off, len, sym_size);
    268		return -ENXIO;
    269	}
    270	len = min_t(size_t, len, sym_size - off);
    271
    272	if (sym->type == NFP_RTSYM_TYPE_ABS) {
    273		u8 tmp[8];
    274
    275		put_unaligned_le64(sym->addr, tmp);
    276		memcpy(buf, &tmp[off], len);
    277
    278		return len;
    279	}
    280
    281	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
    282	if (err)
    283		return err;
    284
    285	return nfp_cpp_read(cpp, cpp_id, addr, buf, len);
    286}
    287
    288int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
    289		   void *buf, size_t len)
    290{
    291	return __nfp_rtsym_read(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
    292}
    293
    294int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
    295		      u8 action, u8 token, u64 off, u32 *value)
    296{
    297	u32 cpp_id;
    298	u64 addr;
    299	int err;
    300
    301	if (off + 4 > nfp_rtsym_size(sym)) {
    302		nfp_err(cpp, "rtsym '%s': readl out of bounds: off: %lld + 4 > size: %lld\n",
    303			sym->name, off, nfp_rtsym_size(sym));
    304		return -ENXIO;
    305	}
    306
    307	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
    308	if (err)
    309		return err;
    310
    311	return nfp_cpp_readl(cpp, cpp_id, addr, value);
    312}
    313
    314int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
    315		    u32 *value)
    316{
    317	return __nfp_rtsym_readl(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
    318}
    319
    320int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
    321		      u8 action, u8 token, u64 off, u64 *value)
    322{
    323	u32 cpp_id;
    324	u64 addr;
    325	int err;
    326
    327	if (off + 8 > nfp_rtsym_size(sym)) {
    328		nfp_err(cpp, "rtsym '%s': readq out of bounds: off: %lld + 8 > size: %lld\n",
    329			sym->name, off, nfp_rtsym_size(sym));
    330		return -ENXIO;
    331	}
    332
    333	if (sym->type == NFP_RTSYM_TYPE_ABS) {
    334		*value = sym->addr;
    335		return 0;
    336	}
    337
    338	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
    339	if (err)
    340		return err;
    341
    342	return nfp_cpp_readq(cpp, cpp_id, addr, value);
    343}
    344
    345int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
    346		    u64 *value)
    347{
    348	return __nfp_rtsym_readq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
    349}
    350
    351int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
    352		      u8 action, u8 token, u64 off, void *buf, size_t len)
    353{
    354	u64 sym_size = nfp_rtsym_size(sym);
    355	u32 cpp_id;
    356	u64 addr;
    357	int err;
    358
    359	if (off > sym_size) {
    360		nfp_err(cpp, "rtsym '%s': write out of bounds: off: %lld + len: %zd > size: %lld\n",
    361			sym->name, off, len, sym_size);
    362		return -ENXIO;
    363	}
    364	len = min_t(size_t, len, sym_size - off);
    365
    366	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
    367	if (err)
    368		return err;
    369
    370	return nfp_cpp_write(cpp, cpp_id, addr, buf, len);
    371}
    372
    373int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
    374		    void *buf, size_t len)
    375{
    376	return __nfp_rtsym_write(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len);
    377}
    378
    379int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
    380		       u8 action, u8 token, u64 off, u32 value)
    381{
    382	u32 cpp_id;
    383	u64 addr;
    384	int err;
    385
    386	if (off + 4 > nfp_rtsym_size(sym)) {
    387		nfp_err(cpp, "rtsym '%s': writel out of bounds: off: %lld + 4 > size: %lld\n",
    388			sym->name, off, nfp_rtsym_size(sym));
    389		return -ENXIO;
    390	}
    391
    392	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
    393	if (err)
    394		return err;
    395
    396	return nfp_cpp_writel(cpp, cpp_id, addr, value);
    397}
    398
    399int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
    400		     u32 value)
    401{
    402	return __nfp_rtsym_writel(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
    403}
    404
    405int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym,
    406		       u8 action, u8 token, u64 off, u64 value)
    407{
    408	u32 cpp_id;
    409	u64 addr;
    410	int err;
    411
    412	if (off + 8 > nfp_rtsym_size(sym)) {
    413		nfp_err(cpp, "rtsym '%s': writeq out of bounds: off: %lld + 8 > size: %lld\n",
    414			sym->name, off, nfp_rtsym_size(sym));
    415		return -ENXIO;
    416	}
    417
    418	err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr);
    419	if (err)
    420		return err;
    421
    422	return nfp_cpp_writeq(cpp, cpp_id, addr, value);
    423}
    424
    425int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off,
    426		     u64 value)
    427{
    428	return __nfp_rtsym_writeq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value);
    429}
    430
    431/**
    432 * nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol
    433 * @rtbl:	NFP RTsym table
    434 * @name:	Symbol name
    435 * @error:	Poniter to error code (optional)
    436 *
    437 * Lookup a symbol, map, read it and return it's value. Value of the symbol
    438 * will be interpreted as a simple little-endian unsigned value. Symbol can
    439 * be 4 or 8 bytes in size.
    440 *
    441 * Return: value read, on error sets the error and returns ~0ULL.
    442 */
    443u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name,
    444		      int *error)
    445{
    446	const struct nfp_rtsym *sym;
    447	u32 val32;
    448	u64 val;
    449	int err;
    450
    451	sym = nfp_rtsym_lookup(rtbl, name);
    452	if (!sym) {
    453		err = -ENOENT;
    454		goto exit;
    455	}
    456
    457	switch (nfp_rtsym_size(sym)) {
    458	case 4:
    459		err = nfp_rtsym_readl(rtbl->cpp, sym, 0, &val32);
    460		val = val32;
    461		break;
    462	case 8:
    463		err = nfp_rtsym_readq(rtbl->cpp, sym, 0, &val);
    464		break;
    465	default:
    466		nfp_err(rtbl->cpp,
    467			"rtsym '%s': unsupported or non-scalar size: %lld\n",
    468			name, nfp_rtsym_size(sym));
    469		err = -EINVAL;
    470		break;
    471	}
    472
    473exit:
    474	if (error)
    475		*error = err;
    476
    477	if (err)
    478		return ~0ULL;
    479	return val;
    480}
    481
    482/**
    483 * nfp_rtsym_write_le() - Write an unsigned scalar value to a symbol
    484 * @rtbl:	NFP RTsym table
    485 * @name:	Symbol name
    486 * @value:	Value to write
    487 *
    488 * Lookup a symbol and write a value to it. Symbol can be 4 or 8 bytes in size.
    489 * If 4 bytes then the lower 32-bits of 'value' are used. Value will be
    490 * written as simple little-endian unsigned value.
    491 *
    492 * Return: 0 on success or error code.
    493 */
    494int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name,
    495		       u64 value)
    496{
    497	const struct nfp_rtsym *sym;
    498	int err;
    499
    500	sym = nfp_rtsym_lookup(rtbl, name);
    501	if (!sym)
    502		return -ENOENT;
    503
    504	switch (nfp_rtsym_size(sym)) {
    505	case 4:
    506		err = nfp_rtsym_writel(rtbl->cpp, sym, 0, value);
    507		break;
    508	case 8:
    509		err = nfp_rtsym_writeq(rtbl->cpp, sym, 0, value);
    510		break;
    511	default:
    512		nfp_err(rtbl->cpp,
    513			"rtsym '%s': unsupported or non-scalar size: %lld\n",
    514			name, nfp_rtsym_size(sym));
    515		err = -EINVAL;
    516		break;
    517	}
    518
    519	return err;
    520}
    521
    522u8 __iomem *
    523nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id,
    524	      unsigned int min_size, struct nfp_cpp_area **area)
    525{
    526	const struct nfp_rtsym *sym;
    527	u8 __iomem *mem;
    528	u32 cpp_id;
    529	u64 addr;
    530	int err;
    531
    532	sym = nfp_rtsym_lookup(rtbl, name);
    533	if (!sym)
    534		return (u8 __iomem *)ERR_PTR(-ENOENT);
    535
    536	err = nfp_rtsym_to_dest(rtbl->cpp, sym, NFP_CPP_ACTION_RW, 0, 0,
    537				&cpp_id, &addr);
    538	if (err) {
    539		nfp_err(rtbl->cpp, "rtsym '%s': mapping failed\n", name);
    540		return (u8 __iomem *)ERR_PTR(err);
    541	}
    542
    543	if (sym->size < min_size) {
    544		nfp_err(rtbl->cpp, "rtsym '%s': too small\n", name);
    545		return (u8 __iomem *)ERR_PTR(-EINVAL);
    546	}
    547
    548	mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, addr, sym->size, area);
    549	if (IS_ERR(mem)) {
    550		nfp_err(rtbl->cpp, "rtysm '%s': failed to map: %ld\n",
    551			name, PTR_ERR(mem));
    552		return mem;
    553	}
    554
    555	return mem;
    556}