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

flash.c (12560B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/kernel.h>
      3#include <linux/fs.h>
      4#include <linux/semaphore.h>
      5#include <linux/slab.h>
      6#include <linux/uaccess.h>
      7#include <linux/of.h>
      8#include <asm/rtas.h>
      9
     10#include "cxl.h"
     11#include "hcalls.h"
     12
     13#define DOWNLOAD_IMAGE 1
     14#define VALIDATE_IMAGE 2
     15
     16struct ai_header {
     17	u16 version;
     18	u8  reserved0[6];
     19	u16 vendor;
     20	u16 device;
     21	u16 subsystem_vendor;
     22	u16 subsystem;
     23	u64 image_offset;
     24	u64 image_length;
     25	u8  reserved1[96];
     26};
     27
     28static struct semaphore sem;
     29static unsigned long *buffer[CXL_AI_MAX_ENTRIES];
     30static struct sg_list *le;
     31static u64 continue_token;
     32static unsigned int transfer;
     33
     34struct update_props_workarea {
     35	__be32 phandle;
     36	__be32 state;
     37	__be64 reserved;
     38	__be32 nprops;
     39} __packed;
     40
     41struct update_nodes_workarea {
     42	__be32 state;
     43	__be64 unit_address;
     44	__be32 reserved;
     45} __packed;
     46
     47#define DEVICE_SCOPE 3
     48#define NODE_ACTION_MASK	0xff000000
     49#define NODE_COUNT_MASK		0x00ffffff
     50#define OPCODE_DELETE	0x01000000
     51#define OPCODE_UPDATE	0x02000000
     52#define OPCODE_ADD	0x03000000
     53
     54static int rcall(int token, char *buf, s32 scope)
     55{
     56	int rc;
     57
     58	spin_lock(&rtas_data_buf_lock);
     59
     60	memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
     61	rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope);
     62	memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
     63
     64	spin_unlock(&rtas_data_buf_lock);
     65	return rc;
     66}
     67
     68static int update_property(struct device_node *dn, const char *name,
     69			   u32 vd, char *value)
     70{
     71	struct property *new_prop;
     72	u32 *val;
     73	int rc;
     74
     75	new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
     76	if (!new_prop)
     77		return -ENOMEM;
     78
     79	new_prop->name = kstrdup(name, GFP_KERNEL);
     80	if (!new_prop->name) {
     81		kfree(new_prop);
     82		return -ENOMEM;
     83	}
     84
     85	new_prop->length = vd;
     86	new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
     87	if (!new_prop->value) {
     88		kfree(new_prop->name);
     89		kfree(new_prop);
     90		return -ENOMEM;
     91	}
     92	memcpy(new_prop->value, value, vd);
     93
     94	val = (u32 *)new_prop->value;
     95	rc = cxl_update_properties(dn, new_prop);
     96	pr_devel("%pOFn: update property (%s, length: %i, value: %#x)\n",
     97		  dn, name, vd, be32_to_cpu(*val));
     98
     99	if (rc) {
    100		kfree(new_prop->name);
    101		kfree(new_prop->value);
    102		kfree(new_prop);
    103	}
    104	return rc;
    105}
    106
    107static int update_node(__be32 phandle, s32 scope)
    108{
    109	struct update_props_workarea *upwa;
    110	struct device_node *dn;
    111	int i, rc, ret;
    112	char *prop_data;
    113	char *buf;
    114	int token;
    115	u32 nprops;
    116	u32 vd;
    117
    118	token = rtas_token("ibm,update-properties");
    119	if (token == RTAS_UNKNOWN_SERVICE)
    120		return -EINVAL;
    121
    122	buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
    123	if (!buf)
    124		return -ENOMEM;
    125
    126	dn = of_find_node_by_phandle(be32_to_cpu(phandle));
    127	if (!dn) {
    128		kfree(buf);
    129		return -ENOENT;
    130	}
    131
    132	upwa = (struct update_props_workarea *)&buf[0];
    133	upwa->phandle = phandle;
    134	do {
    135		rc = rcall(token, buf, scope);
    136		if (rc < 0)
    137			break;
    138
    139		prop_data = buf + sizeof(*upwa);
    140		nprops = be32_to_cpu(upwa->nprops);
    141
    142		if (*prop_data == 0) {
    143			prop_data++;
    144			vd = be32_to_cpu(*(__be32 *)prop_data);
    145			prop_data += vd + sizeof(vd);
    146			nprops--;
    147		}
    148
    149		for (i = 0; i < nprops; i++) {
    150			char *prop_name;
    151
    152			prop_name = prop_data;
    153			prop_data += strlen(prop_name) + 1;
    154			vd = be32_to_cpu(*(__be32 *)prop_data);
    155			prop_data += sizeof(vd);
    156
    157			if ((vd != 0x00000000) && (vd != 0x80000000)) {
    158				ret = update_property(dn, prop_name, vd,
    159						prop_data);
    160				if (ret)
    161					pr_err("cxl: Could not update property %s - %i\n",
    162					       prop_name, ret);
    163
    164				prop_data += vd;
    165			}
    166		}
    167	} while (rc == 1);
    168
    169	of_node_put(dn);
    170	kfree(buf);
    171	return rc;
    172}
    173
    174static int update_devicetree(struct cxl *adapter, s32 scope)
    175{
    176	struct update_nodes_workarea *unwa;
    177	u32 action, node_count;
    178	int token, rc, i;
    179	__be32 *data, phandle;
    180	char *buf;
    181
    182	token = rtas_token("ibm,update-nodes");
    183	if (token == RTAS_UNKNOWN_SERVICE)
    184		return -EINVAL;
    185
    186	buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
    187	if (!buf)
    188		return -ENOMEM;
    189
    190	unwa = (struct update_nodes_workarea *)&buf[0];
    191	unwa->unit_address = cpu_to_be64(adapter->guest->handle);
    192	do {
    193		rc = rcall(token, buf, scope);
    194		if (rc && rc != 1)
    195			break;
    196
    197		data = (__be32 *)buf + 4;
    198		while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
    199			action = be32_to_cpu(*data) & NODE_ACTION_MASK;
    200			node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
    201			pr_devel("device reconfiguration - action: %#x, nodes: %#x\n",
    202				 action, node_count);
    203			data++;
    204
    205			for (i = 0; i < node_count; i++) {
    206				phandle = *data++;
    207
    208				switch (action) {
    209				case OPCODE_DELETE:
    210					/* nothing to do */
    211					break;
    212				case OPCODE_UPDATE:
    213					update_node(phandle, scope);
    214					break;
    215				case OPCODE_ADD:
    216					/* nothing to do, just move pointer */
    217					data++;
    218					break;
    219				}
    220			}
    221		}
    222	} while (rc == 1);
    223
    224	kfree(buf);
    225	return 0;
    226}
    227
    228static int handle_image(struct cxl *adapter, int operation,
    229			long (*fct)(u64, u64, u64, u64 *),
    230			struct cxl_adapter_image *ai)
    231{
    232	size_t mod, s_copy, len_chunk = 0;
    233	struct ai_header *header = NULL;
    234	unsigned int entries = 0, i;
    235	void *dest, *from;
    236	int rc = 0, need_header;
    237
    238	/* base adapter image header */
    239	need_header = (ai->flags & CXL_AI_NEED_HEADER);
    240	if (need_header) {
    241		header = kzalloc(sizeof(struct ai_header), GFP_KERNEL);
    242		if (!header)
    243			return -ENOMEM;
    244		header->version = cpu_to_be16(1);
    245		header->vendor = cpu_to_be16(adapter->guest->vendor);
    246		header->device = cpu_to_be16(adapter->guest->device);
    247		header->subsystem_vendor = cpu_to_be16(adapter->guest->subsystem_vendor);
    248		header->subsystem = cpu_to_be16(adapter->guest->subsystem);
    249		header->image_offset = cpu_to_be64(CXL_AI_HEADER_SIZE);
    250		header->image_length = cpu_to_be64(ai->len_image);
    251	}
    252
    253	/* number of entries in the list */
    254	len_chunk = ai->len_data;
    255	if (need_header)
    256		len_chunk += CXL_AI_HEADER_SIZE;
    257
    258	entries = len_chunk / CXL_AI_BUFFER_SIZE;
    259	mod = len_chunk % CXL_AI_BUFFER_SIZE;
    260	if (mod)
    261		entries++;
    262
    263	if (entries > CXL_AI_MAX_ENTRIES) {
    264		rc = -EINVAL;
    265		goto err;
    266	}
    267
    268	/*          < -- MAX_CHUNK_SIZE = 4096 * 256 = 1048576 bytes -->
    269	 * chunk 0  ----------------------------------------------------
    270	 *          | header   |  data                                 |
    271	 *          ----------------------------------------------------
    272	 * chunk 1  ----------------------------------------------------
    273	 *          | data                                             |
    274	 *          ----------------------------------------------------
    275	 * ....
    276	 * chunk n  ----------------------------------------------------
    277	 *          | data                                             |
    278	 *          ----------------------------------------------------
    279	 */
    280	from = (void *) ai->data;
    281	for (i = 0; i < entries; i++) {
    282		dest = buffer[i];
    283		s_copy = CXL_AI_BUFFER_SIZE;
    284
    285		if ((need_header) && (i == 0)) {
    286			/* add adapter image header */
    287			memcpy(buffer[i], header, sizeof(struct ai_header));
    288			s_copy = CXL_AI_BUFFER_SIZE - CXL_AI_HEADER_SIZE;
    289			dest += CXL_AI_HEADER_SIZE; /* image offset */
    290		}
    291		if ((i == (entries - 1)) && mod)
    292			s_copy = mod;
    293
    294		/* copy data */
    295		if (copy_from_user(dest, from, s_copy))
    296			goto err;
    297
    298		/* fill in the list */
    299		le[i].phys_addr = cpu_to_be64(virt_to_phys(buffer[i]));
    300		le[i].len = cpu_to_be64(CXL_AI_BUFFER_SIZE);
    301		if ((i == (entries - 1)) && mod)
    302			le[i].len = cpu_to_be64(mod);
    303		from += s_copy;
    304	}
    305	pr_devel("%s (op: %i, need header: %i, entries: %i, token: %#llx)\n",
    306		 __func__, operation, need_header, entries, continue_token);
    307
    308	/*
    309	 * download/validate the adapter image to the coherent
    310	 * platform facility
    311	 */
    312	rc = fct(adapter->guest->handle, virt_to_phys(le), entries,
    313		&continue_token);
    314	if (rc == 0) /* success of download/validation operation */
    315		continue_token = 0;
    316
    317err:
    318	kfree(header);
    319
    320	return rc;
    321}
    322
    323static int transfer_image(struct cxl *adapter, int operation,
    324			struct cxl_adapter_image *ai)
    325{
    326	int rc = 0;
    327	int afu;
    328
    329	switch (operation) {
    330	case DOWNLOAD_IMAGE:
    331		rc = handle_image(adapter, operation,
    332				&cxl_h_download_adapter_image, ai);
    333		if (rc < 0) {
    334			pr_devel("resetting adapter\n");
    335			cxl_h_reset_adapter(adapter->guest->handle);
    336		}
    337		return rc;
    338
    339	case VALIDATE_IMAGE:
    340		rc = handle_image(adapter, operation,
    341				&cxl_h_validate_adapter_image, ai);
    342		if (rc < 0) {
    343			pr_devel("resetting adapter\n");
    344			cxl_h_reset_adapter(adapter->guest->handle);
    345			return rc;
    346		}
    347		if (rc == 0) {
    348			pr_devel("remove current afu\n");
    349			for (afu = 0; afu < adapter->slices; afu++)
    350				cxl_guest_remove_afu(adapter->afu[afu]);
    351
    352			pr_devel("resetting adapter\n");
    353			cxl_h_reset_adapter(adapter->guest->handle);
    354
    355			/* The entire image has now been
    356			 * downloaded and the validation has
    357			 * been successfully performed.
    358			 * After that, the partition should call
    359			 * ibm,update-nodes and
    360			 * ibm,update-properties to receive the
    361			 * current configuration
    362			 */
    363			rc = update_devicetree(adapter, DEVICE_SCOPE);
    364			transfer = 1;
    365		}
    366		return rc;
    367	}
    368
    369	return -EINVAL;
    370}
    371
    372static long ioctl_transfer_image(struct cxl *adapter, int operation,
    373				struct cxl_adapter_image __user *uai)
    374{
    375	struct cxl_adapter_image ai;
    376
    377	pr_devel("%s\n", __func__);
    378
    379	if (copy_from_user(&ai, uai, sizeof(struct cxl_adapter_image)))
    380		return -EFAULT;
    381
    382	/*
    383	 * Make sure reserved fields and bits are set to 0
    384	 */
    385	if (ai.reserved1 || ai.reserved2 || ai.reserved3 || ai.reserved4 ||
    386		(ai.flags & ~CXL_AI_ALL))
    387		return -EINVAL;
    388
    389	return transfer_image(adapter, operation, &ai);
    390}
    391
    392static int device_open(struct inode *inode, struct file *file)
    393{
    394	int adapter_num = CXL_DEVT_ADAPTER(inode->i_rdev);
    395	struct cxl *adapter;
    396	int rc = 0, i;
    397
    398	pr_devel("in %s\n", __func__);
    399
    400	BUG_ON(sizeof(struct ai_header) != CXL_AI_HEADER_SIZE);
    401
    402	/* Allows one process to open the device by using a semaphore */
    403	if (down_interruptible(&sem) != 0)
    404		return -EPERM;
    405
    406	if (!(adapter = get_cxl_adapter(adapter_num))) {
    407		rc = -ENODEV;
    408		goto err_unlock;
    409	}
    410
    411	file->private_data = adapter;
    412	continue_token = 0;
    413	transfer = 0;
    414
    415	for (i = 0; i < CXL_AI_MAX_ENTRIES; i++)
    416		buffer[i] = NULL;
    417
    418	/* aligned buffer containing list entries which describes up to
    419	 * 1 megabyte of data (256 entries of 4096 bytes each)
    420	 *  Logical real address of buffer 0  -  Buffer 0 length in bytes
    421	 *  Logical real address of buffer 1  -  Buffer 1 length in bytes
    422	 *  Logical real address of buffer 2  -  Buffer 2 length in bytes
    423	 *  ....
    424	 *  ....
    425	 *  Logical real address of buffer N  -  Buffer N length in bytes
    426	 */
    427	le = (struct sg_list *)get_zeroed_page(GFP_KERNEL);
    428	if (!le) {
    429		rc = -ENOMEM;
    430		goto err;
    431	}
    432
    433	for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
    434		buffer[i] = (unsigned long *)get_zeroed_page(GFP_KERNEL);
    435		if (!buffer[i]) {
    436			rc = -ENOMEM;
    437			goto err1;
    438		}
    439	}
    440
    441	return 0;
    442
    443err1:
    444	for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
    445		if (buffer[i])
    446			free_page((unsigned long) buffer[i]);
    447	}
    448
    449	if (le)
    450		free_page((unsigned long) le);
    451err:
    452	put_device(&adapter->dev);
    453err_unlock:
    454	up(&sem);
    455
    456	return rc;
    457}
    458
    459static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    460{
    461	struct cxl *adapter = file->private_data;
    462
    463	pr_devel("in %s\n", __func__);
    464
    465	if (cmd == CXL_IOCTL_DOWNLOAD_IMAGE)
    466		return ioctl_transfer_image(adapter,
    467					DOWNLOAD_IMAGE,
    468					(struct cxl_adapter_image __user *)arg);
    469	else if (cmd == CXL_IOCTL_VALIDATE_IMAGE)
    470		return ioctl_transfer_image(adapter,
    471					VALIDATE_IMAGE,
    472					(struct cxl_adapter_image __user *)arg);
    473	else
    474		return -EINVAL;
    475}
    476
    477static int device_close(struct inode *inode, struct file *file)
    478{
    479	struct cxl *adapter = file->private_data;
    480	int i;
    481
    482	pr_devel("in %s\n", __func__);
    483
    484	for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
    485		if (buffer[i])
    486			free_page((unsigned long) buffer[i]);
    487	}
    488
    489	if (le)
    490		free_page((unsigned long) le);
    491
    492	up(&sem);
    493	put_device(&adapter->dev);
    494	continue_token = 0;
    495
    496	/* reload the module */
    497	if (transfer)
    498		cxl_guest_reload_module(adapter);
    499	else {
    500		pr_devel("resetting adapter\n");
    501		cxl_h_reset_adapter(adapter->guest->handle);
    502	}
    503
    504	transfer = 0;
    505	return 0;
    506}
    507
    508static const struct file_operations fops = {
    509	.owner		= THIS_MODULE,
    510	.open		= device_open,
    511	.unlocked_ioctl	= device_ioctl,
    512	.compat_ioctl	= compat_ptr_ioctl,
    513	.release	= device_close,
    514};
    515
    516void cxl_guest_remove_chardev(struct cxl *adapter)
    517{
    518	cdev_del(&adapter->guest->cdev);
    519}
    520
    521int cxl_guest_add_chardev(struct cxl *adapter)
    522{
    523	dev_t devt;
    524	int rc;
    525
    526	devt = MKDEV(MAJOR(cxl_get_dev()), CXL_CARD_MINOR(adapter));
    527	cdev_init(&adapter->guest->cdev, &fops);
    528	if ((rc = cdev_add(&adapter->guest->cdev, devt, 1))) {
    529		dev_err(&adapter->dev,
    530			"Unable to add chardev on adapter (card%i): %i\n",
    531			adapter->adapter_num, rc);
    532		goto err;
    533	}
    534	adapter->dev.devt = devt;
    535	sema_init(&sem, 1);
    536err:
    537	return rc;
    538}