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

mem.c (7039B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2// Copyright(c) 2021 Intel Corporation. All rights reserved.
      3
      4#include <linux/platform_device.h>
      5#include <linux/mod_devicetable.h>
      6#include <linux/module.h>
      7#include <linux/delay.h>
      8#include <linux/sizes.h>
      9#include <linux/bits.h>
     10#include <cxlmem.h>
     11
     12#define LSA_SIZE SZ_128K
     13#define EFFECT(x) (1U << x)
     14
     15static struct cxl_cel_entry mock_cel[] = {
     16	{
     17		.opcode = cpu_to_le16(CXL_MBOX_OP_GET_SUPPORTED_LOGS),
     18		.effect = cpu_to_le16(0),
     19	},
     20	{
     21		.opcode = cpu_to_le16(CXL_MBOX_OP_IDENTIFY),
     22		.effect = cpu_to_le16(0),
     23	},
     24	{
     25		.opcode = cpu_to_le16(CXL_MBOX_OP_GET_LSA),
     26		.effect = cpu_to_le16(0),
     27	},
     28	{
     29		.opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA),
     30		.effect = cpu_to_le16(EFFECT(1) | EFFECT(2)),
     31	},
     32	{
     33		.opcode = cpu_to_le16(CXL_MBOX_OP_GET_HEALTH_INFO),
     34		.effect = cpu_to_le16(0),
     35	},
     36};
     37
     38/* See CXL 2.0 Table 181 Get Health Info Output Payload */
     39struct cxl_mbox_health_info {
     40	u8 health_status;
     41	u8 media_status;
     42	u8 ext_status;
     43	u8 life_used;
     44	__le16 temperature;
     45	__le32 dirty_shutdowns;
     46	__le32 volatile_errors;
     47	__le32 pmem_errors;
     48} __packed;
     49
     50static struct {
     51	struct cxl_mbox_get_supported_logs gsl;
     52	struct cxl_gsl_entry entry;
     53} mock_gsl_payload = {
     54	.gsl = {
     55		.entries = cpu_to_le16(1),
     56	},
     57	.entry = {
     58		.uuid = DEFINE_CXL_CEL_UUID,
     59		.size = cpu_to_le32(sizeof(mock_cel)),
     60	},
     61};
     62
     63static int mock_gsl(struct cxl_mbox_cmd *cmd)
     64{
     65	if (cmd->size_out < sizeof(mock_gsl_payload))
     66		return -EINVAL;
     67
     68	memcpy(cmd->payload_out, &mock_gsl_payload, sizeof(mock_gsl_payload));
     69	cmd->size_out = sizeof(mock_gsl_payload);
     70
     71	return 0;
     72}
     73
     74static int mock_get_log(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
     75{
     76	struct cxl_mbox_get_log *gl = cmd->payload_in;
     77	u32 offset = le32_to_cpu(gl->offset);
     78	u32 length = le32_to_cpu(gl->length);
     79	uuid_t uuid = DEFINE_CXL_CEL_UUID;
     80	void *data = &mock_cel;
     81
     82	if (cmd->size_in < sizeof(*gl))
     83		return -EINVAL;
     84	if (length > cxlds->payload_size)
     85		return -EINVAL;
     86	if (offset + length > sizeof(mock_cel))
     87		return -EINVAL;
     88	if (!uuid_equal(&gl->uuid, &uuid))
     89		return -EINVAL;
     90	if (length > cmd->size_out)
     91		return -EINVAL;
     92
     93	memcpy(cmd->payload_out, data + offset, length);
     94
     95	return 0;
     96}
     97
     98static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
     99{
    100	struct platform_device *pdev = to_platform_device(cxlds->dev);
    101	struct cxl_mbox_identify id = {
    102		.fw_revision = { "mock fw v1 " },
    103		.lsa_size = cpu_to_le32(LSA_SIZE),
    104		/* FIXME: Add partition support */
    105		.partition_align = cpu_to_le64(0),
    106	};
    107	u64 capacity = 0;
    108	int i;
    109
    110	if (cmd->size_out < sizeof(id))
    111		return -EINVAL;
    112
    113	for (i = 0; i < 2; i++) {
    114		struct resource *res;
    115
    116		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
    117		if (!res)
    118			break;
    119
    120		capacity += resource_size(res) / CXL_CAPACITY_MULTIPLIER;
    121
    122		if (le64_to_cpu(id.partition_align))
    123			continue;
    124
    125		if (res->desc == IORES_DESC_PERSISTENT_MEMORY)
    126			id.persistent_capacity = cpu_to_le64(
    127				resource_size(res) / CXL_CAPACITY_MULTIPLIER);
    128		else
    129			id.volatile_capacity = cpu_to_le64(
    130				resource_size(res) / CXL_CAPACITY_MULTIPLIER);
    131	}
    132
    133	id.total_capacity = cpu_to_le64(capacity);
    134
    135	memcpy(cmd->payload_out, &id, sizeof(id));
    136
    137	return 0;
    138}
    139
    140static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
    141{
    142	struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in;
    143	void *lsa = dev_get_drvdata(cxlds->dev);
    144	u32 offset, length;
    145
    146	if (sizeof(*get_lsa) > cmd->size_in)
    147		return -EINVAL;
    148	offset = le32_to_cpu(get_lsa->offset);
    149	length = le32_to_cpu(get_lsa->length);
    150	if (offset + length > LSA_SIZE)
    151		return -EINVAL;
    152	if (length > cmd->size_out)
    153		return -EINVAL;
    154
    155	memcpy(cmd->payload_out, lsa + offset, length);
    156	return 0;
    157}
    158
    159static int mock_set_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
    160{
    161	struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in;
    162	void *lsa = dev_get_drvdata(cxlds->dev);
    163	u32 offset, length;
    164
    165	if (sizeof(*set_lsa) > cmd->size_in)
    166		return -EINVAL;
    167	offset = le32_to_cpu(set_lsa->offset);
    168	length = cmd->size_in - sizeof(*set_lsa);
    169	if (offset + length > LSA_SIZE)
    170		return -EINVAL;
    171
    172	memcpy(lsa + offset, &set_lsa->data[0], length);
    173	return 0;
    174}
    175
    176static int mock_health_info(struct cxl_dev_state *cxlds,
    177			    struct cxl_mbox_cmd *cmd)
    178{
    179	struct cxl_mbox_health_info health_info = {
    180		/* set flags for maint needed, perf degraded, hw replacement */
    181		.health_status = 0x7,
    182		/* set media status to "All Data Lost" */
    183		.media_status = 0x3,
    184		/*
    185		 * set ext_status flags for:
    186		 *  ext_life_used: normal,
    187		 *  ext_temperature: critical,
    188		 *  ext_corrected_volatile: warning,
    189		 *  ext_corrected_persistent: normal,
    190		 */
    191		.ext_status = 0x18,
    192		.life_used = 15,
    193		.temperature = cpu_to_le16(25),
    194		.dirty_shutdowns = cpu_to_le32(10),
    195		.volatile_errors = cpu_to_le32(20),
    196		.pmem_errors = cpu_to_le32(30),
    197	};
    198
    199	if (cmd->size_out < sizeof(health_info))
    200		return -EINVAL;
    201
    202	memcpy(cmd->payload_out, &health_info, sizeof(health_info));
    203	return 0;
    204}
    205
    206static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
    207{
    208	struct device *dev = cxlds->dev;
    209	int rc = -EIO;
    210
    211	switch (cmd->opcode) {
    212	case CXL_MBOX_OP_GET_SUPPORTED_LOGS:
    213		rc = mock_gsl(cmd);
    214		break;
    215	case CXL_MBOX_OP_GET_LOG:
    216		rc = mock_get_log(cxlds, cmd);
    217		break;
    218	case CXL_MBOX_OP_IDENTIFY:
    219		rc = mock_id(cxlds, cmd);
    220		break;
    221	case CXL_MBOX_OP_GET_LSA:
    222		rc = mock_get_lsa(cxlds, cmd);
    223		break;
    224	case CXL_MBOX_OP_SET_LSA:
    225		rc = mock_set_lsa(cxlds, cmd);
    226		break;
    227	case CXL_MBOX_OP_GET_HEALTH_INFO:
    228		rc = mock_health_info(cxlds, cmd);
    229		break;
    230	default:
    231		break;
    232	}
    233
    234	dev_dbg(dev, "opcode: %#x sz_in: %zd sz_out: %zd rc: %d\n", cmd->opcode,
    235		cmd->size_in, cmd->size_out, rc);
    236
    237	return rc;
    238}
    239
    240static void label_area_release(void *lsa)
    241{
    242	vfree(lsa);
    243}
    244
    245static int cxl_mock_mem_probe(struct platform_device *pdev)
    246{
    247	struct device *dev = &pdev->dev;
    248	struct cxl_memdev *cxlmd;
    249	struct cxl_dev_state *cxlds;
    250	void *lsa;
    251	int rc;
    252
    253	lsa = vmalloc(LSA_SIZE);
    254	if (!lsa)
    255		return -ENOMEM;
    256	rc = devm_add_action_or_reset(dev, label_area_release, lsa);
    257	if (rc)
    258		return rc;
    259	dev_set_drvdata(dev, lsa);
    260
    261	cxlds = cxl_dev_state_create(dev);
    262	if (IS_ERR(cxlds))
    263		return PTR_ERR(cxlds);
    264
    265	cxlds->serial = pdev->id;
    266	cxlds->mbox_send = cxl_mock_mbox_send;
    267	cxlds->payload_size = SZ_4K;
    268
    269	rc = cxl_enumerate_cmds(cxlds);
    270	if (rc)
    271		return rc;
    272
    273	rc = cxl_dev_state_identify(cxlds);
    274	if (rc)
    275		return rc;
    276
    277	rc = cxl_mem_create_range_info(cxlds);
    278	if (rc)
    279		return rc;
    280
    281	cxlmd = devm_cxl_add_memdev(cxlds);
    282	if (IS_ERR(cxlmd))
    283		return PTR_ERR(cxlmd);
    284
    285	if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM))
    286		rc = devm_cxl_add_nvdimm(dev, cxlmd);
    287
    288	return 0;
    289}
    290
    291static const struct platform_device_id cxl_mock_mem_ids[] = {
    292	{ .name = "cxl_mem", },
    293	{ },
    294};
    295MODULE_DEVICE_TABLE(platform, cxl_mock_mem_ids);
    296
    297static struct platform_driver cxl_mock_mem_driver = {
    298	.probe = cxl_mock_mem_probe,
    299	.id_table = cxl_mock_mem_ids,
    300	.driver = {
    301		.name = KBUILD_MODNAME,
    302	},
    303};
    304
    305module_platform_driver(cxl_mock_mem_driver);
    306MODULE_LICENSE("GPL v2");
    307MODULE_IMPORT_NS(CXL);