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

sdsi.c (14542B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Intel Software Defined Silicon driver
      4 *
      5 * Copyright (c) 2022, Intel Corporation.
      6 * All Rights Reserved.
      7 *
      8 * Author: "David E. Box" <david.e.box@linux.intel.com>
      9 */
     10
     11#include <linux/auxiliary_bus.h>
     12#include <linux/bits.h>
     13#include <linux/bitfield.h>
     14#include <linux/device.h>
     15#include <linux/iopoll.h>
     16#include <linux/kernel.h>
     17#include <linux/module.h>
     18#include <linux/pci.h>
     19#include <linux/slab.h>
     20#include <linux/sysfs.h>
     21#include <linux/types.h>
     22#include <linux/uaccess.h>
     23
     24#include "vsec.h"
     25
     26#define ACCESS_TYPE_BARID		2
     27#define ACCESS_TYPE_LOCAL		3
     28
     29#define SDSI_MIN_SIZE_DWORDS		276
     30#define SDSI_SIZE_CONTROL		8
     31#define SDSI_SIZE_MAILBOX		1024
     32#define SDSI_SIZE_REGS			72
     33#define SDSI_SIZE_CMD			sizeof(u64)
     34
     35/*
     36 * Write messages are currently up to the size of the mailbox
     37 * while read messages are up to 4 times the size of the
     38 * mailbox, sent in packets
     39 */
     40#define SDSI_SIZE_WRITE_MSG		SDSI_SIZE_MAILBOX
     41#define SDSI_SIZE_READ_MSG		(SDSI_SIZE_MAILBOX * 4)
     42
     43#define SDSI_ENABLED_FEATURES_OFFSET	16
     44#define SDSI_ENABLED			BIT(3)
     45#define SDSI_SOCKET_ID_OFFSET		64
     46#define SDSI_SOCKET_ID			GENMASK(3, 0)
     47
     48#define SDSI_MBOX_CMD_SUCCESS		0x40
     49#define SDSI_MBOX_CMD_TIMEOUT		0x80
     50
     51#define MBOX_TIMEOUT_US			2000
     52#define MBOX_TIMEOUT_ACQUIRE_US		1000
     53#define MBOX_POLLING_PERIOD_US		100
     54#define MBOX_ACQUIRE_NUM_RETRIES	5
     55#define MBOX_ACQUIRE_RETRY_DELAY_MS	500
     56#define MBOX_MAX_PACKETS		4
     57
     58#define MBOX_OWNER_NONE			0x00
     59#define MBOX_OWNER_INBAND		0x01
     60
     61#define CTRL_RUN_BUSY			BIT(0)
     62#define CTRL_READ_WRITE			BIT(1)
     63#define CTRL_SOM			BIT(2)
     64#define CTRL_EOM			BIT(3)
     65#define CTRL_OWNER			GENMASK(5, 4)
     66#define CTRL_COMPLETE			BIT(6)
     67#define CTRL_READY			BIT(7)
     68#define CTRL_STATUS			GENMASK(15, 8)
     69#define CTRL_PACKET_SIZE		GENMASK(31, 16)
     70#define CTRL_MSG_SIZE			GENMASK(63, 48)
     71
     72#define DISC_TABLE_SIZE			12
     73#define DT_ACCESS_TYPE			GENMASK(3, 0)
     74#define DT_SIZE				GENMASK(27, 12)
     75#define DT_TBIR				GENMASK(2, 0)
     76#define DT_OFFSET(v)			((v) & GENMASK(31, 3))
     77
     78enum sdsi_command {
     79	SDSI_CMD_PROVISION_AKC		= 0x04,
     80	SDSI_CMD_PROVISION_CAP		= 0x08,
     81	SDSI_CMD_READ_STATE		= 0x10,
     82};
     83
     84struct sdsi_mbox_info {
     85	u64	*payload;
     86	void	*buffer;
     87	int	size;
     88};
     89
     90struct disc_table {
     91	u32	access_info;
     92	u32	guid;
     93	u32	offset;
     94};
     95
     96struct sdsi_priv {
     97	struct mutex		mb_lock;	/* Mailbox access lock */
     98	struct device		*dev;
     99	void __iomem		*control_addr;
    100	void __iomem		*mbox_addr;
    101	void __iomem		*regs_addr;
    102	u32			guid;
    103	bool			sdsi_enabled;
    104};
    105
    106/* SDSi mailbox operations must be performed using 64bit mov instructions */
    107static __always_inline void
    108sdsi_memcpy64_toio(u64 __iomem *to, const u64 *from, size_t count_bytes)
    109{
    110	size_t count = count_bytes / sizeof(*to);
    111	int i;
    112
    113	for (i = 0; i < count; i++)
    114		writeq(from[i], &to[i]);
    115}
    116
    117static __always_inline void
    118sdsi_memcpy64_fromio(u64 *to, const u64 __iomem *from, size_t count_bytes)
    119{
    120	size_t count = count_bytes / sizeof(*to);
    121	int i;
    122
    123	for (i = 0; i < count; i++)
    124		to[i] = readq(&from[i]);
    125}
    126
    127static inline void sdsi_complete_transaction(struct sdsi_priv *priv)
    128{
    129	u64 control = FIELD_PREP(CTRL_COMPLETE, 1);
    130
    131	lockdep_assert_held(&priv->mb_lock);
    132	writeq(control, priv->control_addr);
    133}
    134
    135static int sdsi_status_to_errno(u32 status)
    136{
    137	switch (status) {
    138	case SDSI_MBOX_CMD_SUCCESS:
    139		return 0;
    140	case SDSI_MBOX_CMD_TIMEOUT:
    141		return -ETIMEDOUT;
    142	default:
    143		return -EIO;
    144	}
    145}
    146
    147static int sdsi_mbox_cmd_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info,
    148			      size_t *data_size)
    149{
    150	struct device *dev = priv->dev;
    151	u32 total, loop, eom, status, message_size;
    152	u64 control;
    153	int ret;
    154
    155	lockdep_assert_held(&priv->mb_lock);
    156
    157	/* Format and send the read command */
    158	control = FIELD_PREP(CTRL_EOM, 1) |
    159		  FIELD_PREP(CTRL_SOM, 1) |
    160		  FIELD_PREP(CTRL_RUN_BUSY, 1) |
    161		  FIELD_PREP(CTRL_PACKET_SIZE, info->size);
    162	writeq(control, priv->control_addr);
    163
    164	/* For reads, data sizes that are larger than the mailbox size are read in packets. */
    165	total = 0;
    166	loop = 0;
    167	do {
    168		void *buf = info->buffer + (SDSI_SIZE_MAILBOX * loop);
    169		u32 packet_size;
    170
    171		/* Poll on ready bit */
    172		ret = readq_poll_timeout(priv->control_addr, control, control & CTRL_READY,
    173					 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US);
    174		if (ret)
    175			break;
    176
    177		eom = FIELD_GET(CTRL_EOM, control);
    178		status = FIELD_GET(CTRL_STATUS, control);
    179		packet_size = FIELD_GET(CTRL_PACKET_SIZE, control);
    180		message_size = FIELD_GET(CTRL_MSG_SIZE, control);
    181
    182		ret = sdsi_status_to_errno(status);
    183		if (ret)
    184			break;
    185
    186		/* Only the last packet can be less than the mailbox size. */
    187		if (!eom && packet_size != SDSI_SIZE_MAILBOX) {
    188			dev_err(dev, "Invalid packet size\n");
    189			ret = -EPROTO;
    190			break;
    191		}
    192
    193		if (packet_size > SDSI_SIZE_MAILBOX) {
    194			dev_err(dev, "Packet size too large\n");
    195			ret = -EPROTO;
    196			break;
    197		}
    198
    199		sdsi_memcpy64_fromio(buf, priv->mbox_addr, round_up(packet_size, SDSI_SIZE_CMD));
    200
    201		total += packet_size;
    202
    203		sdsi_complete_transaction(priv);
    204	} while (!eom && ++loop < MBOX_MAX_PACKETS);
    205
    206	if (ret) {
    207		sdsi_complete_transaction(priv);
    208		return ret;
    209	}
    210
    211	if (!eom) {
    212		dev_err(dev, "Exceeded read attempts\n");
    213		return -EPROTO;
    214	}
    215
    216	/* Message size check is only valid for multi-packet transfers */
    217	if (loop && total != message_size)
    218		dev_warn(dev, "Read count %u differs from expected count %u\n",
    219			 total, message_size);
    220
    221	*data_size = total;
    222
    223	return 0;
    224}
    225
    226static int sdsi_mbox_cmd_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
    227{
    228	u64 control;
    229	u32 status;
    230	int ret;
    231
    232	lockdep_assert_held(&priv->mb_lock);
    233
    234	/* Write rest of the payload */
    235	sdsi_memcpy64_toio(priv->mbox_addr + SDSI_SIZE_CMD, info->payload + 1,
    236			   info->size - SDSI_SIZE_CMD);
    237
    238	/* Format and send the write command */
    239	control = FIELD_PREP(CTRL_EOM, 1) |
    240		  FIELD_PREP(CTRL_SOM, 1) |
    241		  FIELD_PREP(CTRL_RUN_BUSY, 1) |
    242		  FIELD_PREP(CTRL_READ_WRITE, 1) |
    243		  FIELD_PREP(CTRL_PACKET_SIZE, info->size);
    244	writeq(control, priv->control_addr);
    245
    246	/* Poll on ready bit */
    247	ret = readq_poll_timeout(priv->control_addr, control, control & CTRL_READY,
    248				 MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_US);
    249
    250	if (ret)
    251		goto release_mbox;
    252
    253	status = FIELD_GET(CTRL_STATUS, control);
    254	ret = sdsi_status_to_errno(status);
    255
    256release_mbox:
    257	sdsi_complete_transaction(priv);
    258
    259	return ret;
    260}
    261
    262static int sdsi_mbox_acquire(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
    263{
    264	u64 control;
    265	u32 owner;
    266	int ret, retries = 0;
    267
    268	lockdep_assert_held(&priv->mb_lock);
    269
    270	/* Check mailbox is available */
    271	control = readq(priv->control_addr);
    272	owner = FIELD_GET(CTRL_OWNER, control);
    273	if (owner != MBOX_OWNER_NONE)
    274		return -EBUSY;
    275
    276	/*
    277	 * If there has been no recent transaction and no one owns the mailbox,
    278	 * we should acquire it in under 1ms. However, if we've accessed it
    279	 * recently it may take up to 2.1 seconds to acquire it again.
    280	 */
    281	do {
    282		/* Write first qword of payload */
    283		writeq(info->payload[0], priv->mbox_addr);
    284
    285		/* Check for ownership */
    286		ret = readq_poll_timeout(priv->control_addr, control,
    287			FIELD_GET(CTRL_OWNER, control) == MBOX_OWNER_INBAND,
    288			MBOX_POLLING_PERIOD_US, MBOX_TIMEOUT_ACQUIRE_US);
    289
    290		if (FIELD_GET(CTRL_OWNER, control) == MBOX_OWNER_NONE &&
    291		    retries++ < MBOX_ACQUIRE_NUM_RETRIES) {
    292			msleep(MBOX_ACQUIRE_RETRY_DELAY_MS);
    293			continue;
    294		}
    295
    296		/* Either we got it or someone else did. */
    297		break;
    298	} while (true);
    299
    300	return ret;
    301}
    302
    303static int sdsi_mbox_write(struct sdsi_priv *priv, struct sdsi_mbox_info *info)
    304{
    305	int ret;
    306
    307	lockdep_assert_held(&priv->mb_lock);
    308
    309	ret = sdsi_mbox_acquire(priv, info);
    310	if (ret)
    311		return ret;
    312
    313	return sdsi_mbox_cmd_write(priv, info);
    314}
    315
    316static int sdsi_mbox_read(struct sdsi_priv *priv, struct sdsi_mbox_info *info, size_t *data_size)
    317{
    318	int ret;
    319
    320	lockdep_assert_held(&priv->mb_lock);
    321
    322	ret = sdsi_mbox_acquire(priv, info);
    323	if (ret)
    324		return ret;
    325
    326	return sdsi_mbox_cmd_read(priv, info, data_size);
    327}
    328
    329static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count,
    330			      enum sdsi_command command)
    331{
    332	struct sdsi_mbox_info info;
    333	int ret;
    334
    335	if (!priv->sdsi_enabled)
    336		return -EPERM;
    337
    338	if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD))
    339		return -EOVERFLOW;
    340
    341	/* Qword aligned message + command qword */
    342	info.size = round_up(count, SDSI_SIZE_CMD) + SDSI_SIZE_CMD;
    343
    344	info.payload = kzalloc(info.size, GFP_KERNEL);
    345	if (!info.payload)
    346		return -ENOMEM;
    347
    348	/* Copy message to payload buffer */
    349	memcpy(info.payload, buf, count);
    350
    351	/* Command is last qword of payload buffer */
    352	info.payload[(info.size - SDSI_SIZE_CMD) / SDSI_SIZE_CMD] = command;
    353
    354	ret = mutex_lock_interruptible(&priv->mb_lock);
    355	if (ret)
    356		goto free_payload;
    357	ret = sdsi_mbox_write(priv, &info);
    358	mutex_unlock(&priv->mb_lock);
    359
    360free_payload:
    361	kfree(info.payload);
    362
    363	if (ret)
    364		return ret;
    365
    366	return count;
    367}
    368
    369static ssize_t provision_akc_write(struct file *filp, struct kobject *kobj,
    370				   struct bin_attribute *attr, char *buf, loff_t off,
    371				   size_t count)
    372{
    373	struct device *dev = kobj_to_dev(kobj);
    374	struct sdsi_priv *priv = dev_get_drvdata(dev);
    375
    376	if (off)
    377		return -ESPIPE;
    378
    379	return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_AKC);
    380}
    381static BIN_ATTR_WO(provision_akc, SDSI_SIZE_WRITE_MSG);
    382
    383static ssize_t provision_cap_write(struct file *filp, struct kobject *kobj,
    384				   struct bin_attribute *attr, char *buf, loff_t off,
    385				   size_t count)
    386{
    387	struct device *dev = kobj_to_dev(kobj);
    388	struct sdsi_priv *priv = dev_get_drvdata(dev);
    389
    390	if (off)
    391		return -ESPIPE;
    392
    393	return sdsi_provision(priv, buf, count, SDSI_CMD_PROVISION_CAP);
    394}
    395static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG);
    396
    397static long state_certificate_read(struct file *filp, struct kobject *kobj,
    398				   struct bin_attribute *attr, char *buf, loff_t off,
    399				   size_t count)
    400{
    401	struct device *dev = kobj_to_dev(kobj);
    402	struct sdsi_priv *priv = dev_get_drvdata(dev);
    403	u64 command = SDSI_CMD_READ_STATE;
    404	struct sdsi_mbox_info info;
    405	size_t size;
    406	int ret;
    407
    408	if (!priv->sdsi_enabled)
    409		return -EPERM;
    410
    411	if (off)
    412		return 0;
    413
    414	/* Buffer for return data */
    415	info.buffer = kmalloc(SDSI_SIZE_READ_MSG, GFP_KERNEL);
    416	if (!info.buffer)
    417		return -ENOMEM;
    418
    419	info.payload = &command;
    420	info.size = sizeof(command);
    421
    422	ret = mutex_lock_interruptible(&priv->mb_lock);
    423	if (ret)
    424		goto free_buffer;
    425	ret = sdsi_mbox_read(priv, &info, &size);
    426	mutex_unlock(&priv->mb_lock);
    427	if (ret < 0)
    428		goto free_buffer;
    429
    430	if (size > count)
    431		size = count;
    432
    433	memcpy(buf, info.buffer, size);
    434
    435free_buffer:
    436	kfree(info.buffer);
    437
    438	if (ret)
    439		return ret;
    440
    441	return size;
    442}
    443static BIN_ATTR(state_certificate, 0400, state_certificate_read, NULL, SDSI_SIZE_READ_MSG);
    444
    445static ssize_t registers_read(struct file *filp, struct kobject *kobj,
    446			      struct bin_attribute *attr, char *buf, loff_t off,
    447			      size_t count)
    448{
    449	struct device *dev = kobj_to_dev(kobj);
    450	struct sdsi_priv *priv = dev_get_drvdata(dev);
    451	void __iomem *addr = priv->regs_addr;
    452
    453	memcpy_fromio(buf, addr + off, count);
    454
    455	return count;
    456}
    457static BIN_ATTR(registers, 0400, registers_read, NULL, SDSI_SIZE_REGS);
    458
    459static struct bin_attribute *sdsi_bin_attrs[] = {
    460	&bin_attr_registers,
    461	&bin_attr_state_certificate,
    462	&bin_attr_provision_akc,
    463	&bin_attr_provision_cap,
    464	NULL
    465};
    466
    467static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf)
    468{
    469	struct sdsi_priv *priv = dev_get_drvdata(dev);
    470
    471	return sysfs_emit(buf, "0x%x\n", priv->guid);
    472}
    473static DEVICE_ATTR_RO(guid);
    474
    475static struct attribute *sdsi_attrs[] = {
    476	&dev_attr_guid.attr,
    477	NULL
    478};
    479
    480static const struct attribute_group sdsi_group = {
    481	.attrs = sdsi_attrs,
    482	.bin_attrs = sdsi_bin_attrs,
    483};
    484__ATTRIBUTE_GROUPS(sdsi);
    485
    486static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent,
    487				   struct disc_table *disc_table, struct resource *disc_res)
    488{
    489	u32 access_type = FIELD_GET(DT_ACCESS_TYPE, disc_table->access_info);
    490	u32 size = FIELD_GET(DT_SIZE, disc_table->access_info);
    491	u32 tbir = FIELD_GET(DT_TBIR, disc_table->offset);
    492	u32 offset = DT_OFFSET(disc_table->offset);
    493	u32 features_offset;
    494	struct resource res = {};
    495
    496	/* Starting location of SDSi MMIO region based on access type */
    497	switch (access_type) {
    498	case ACCESS_TYPE_LOCAL:
    499		if (tbir) {
    500			dev_err(priv->dev, "Unsupported BAR index %u for access type %u\n",
    501				tbir, access_type);
    502			return -EINVAL;
    503		}
    504
    505		/*
    506		 * For access_type LOCAL, the base address is as follows:
    507		 * base address = end of discovery region + base offset + 1
    508		 */
    509		res.start = disc_res->end + offset + 1;
    510		break;
    511
    512	case ACCESS_TYPE_BARID:
    513		res.start = pci_resource_start(parent, tbir) + offset;
    514		break;
    515
    516	default:
    517		dev_err(priv->dev, "Unrecognized access_type %u\n", access_type);
    518		return -EINVAL;
    519	}
    520
    521	res.end = res.start + size * sizeof(u32) - 1;
    522	res.flags = IORESOURCE_MEM;
    523
    524	priv->control_addr = devm_ioremap_resource(priv->dev, &res);
    525	if (IS_ERR(priv->control_addr))
    526		return PTR_ERR(priv->control_addr);
    527
    528	priv->mbox_addr = priv->control_addr + SDSI_SIZE_CONTROL;
    529	priv->regs_addr = priv->mbox_addr + SDSI_SIZE_MAILBOX;
    530
    531	features_offset = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET);
    532	priv->sdsi_enabled = !!(features_offset & SDSI_ENABLED);
    533
    534	return 0;
    535}
    536
    537static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
    538{
    539	struct intel_vsec_device *intel_cap_dev = auxdev_to_ivdev(auxdev);
    540	struct disc_table disc_table;
    541	struct resource *disc_res;
    542	void __iomem *disc_addr;
    543	struct sdsi_priv *priv;
    544	int ret;
    545
    546	priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL);
    547	if (!priv)
    548		return -ENOMEM;
    549
    550	priv->dev = &auxdev->dev;
    551	mutex_init(&priv->mb_lock);
    552	auxiliary_set_drvdata(auxdev, priv);
    553
    554	/* Get the SDSi discovery table */
    555	disc_res = &intel_cap_dev->resource[0];
    556	disc_addr = devm_ioremap_resource(&auxdev->dev, disc_res);
    557	if (IS_ERR(disc_addr))
    558		return PTR_ERR(disc_addr);
    559
    560	memcpy_fromio(&disc_table, disc_addr, DISC_TABLE_SIZE);
    561
    562	priv->guid = disc_table.guid;
    563
    564	/* Map the SDSi mailbox registers */
    565	ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res);
    566	if (ret)
    567		return ret;
    568
    569	return 0;
    570}
    571
    572static const struct auxiliary_device_id sdsi_aux_id_table[] = {
    573	{ .name = "intel_vsec.sdsi" },
    574	{}
    575};
    576MODULE_DEVICE_TABLE(auxiliary, sdsi_aux_id_table);
    577
    578static struct auxiliary_driver sdsi_aux_driver = {
    579	.driver = {
    580		.dev_groups = sdsi_groups,
    581	},
    582	.id_table	= sdsi_aux_id_table,
    583	.probe		= sdsi_probe,
    584	/* No remove. All resources are handled under devm */
    585};
    586module_auxiliary_driver(sdsi_aux_driver);
    587
    588MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
    589MODULE_DESCRIPTION("Intel Software Defined Silicon driver");
    590MODULE_LICENSE("GPL");