Merge branch 'for-7.2/cxl-misc' into cxl-for-next

cxl/region: Fill first free targets[] slot during auto-discovery
cxl/region: Fix out-of-bounds access in cxl_cancel_auto_attach()
tools/testing/cxl: Resolve auto-region decoder targets like real HW
cxl: Align interleave decode/encode helpers with their callers
cxl/test: Add check after kzalloc() memory in alloc_mock_res()
cxl/test: Unregister cxl_acpi in cxl_test_init() error path
cxl/test: Zero out LSA backing memory to avoid leaking to user
cxl/test: Fix integer overflow in mock LSA bounds checks
cxl/test: Verify cmd->size_in before accessing payload
cxl/port: update reference to removed CONFIG_PROVE_CXL_LOCKING
cxl/region: Avoid variable shadowing in region attach paths
cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size
cxl/test: Fix __fortify_panic
cxl/fwctl: Fix __fortify_panic
MAINTAINERS: Add CXL reviewer
cxl/test: Enforce PMD alignment for volatile mock regions
cxl/region: Validate partition index before array access
cxl/memdev: Hold memdev lock during memdev poison injection/clear
This commit is contained in:
Dave Jiang 2026-06-12 09:34:35 -07:00
commit e53ef72033
12 changed files with 178 additions and 82 deletions

View File

@ -6437,6 +6437,7 @@ M: Alison Schofield <alison.schofield@intel.com>
M: Vishal Verma <vishal.l.verma@intel.com>
M: Ira Weiny <ira.weiny@intel.com>
M: Dan Williams <djbw@kernel.org>
R: Li Ming <ming.li@zohomail.com>
L: linux-cxl@vger.kernel.org
S: Maintained
F: Documentation/driver-api/cxl

View File

@ -101,8 +101,8 @@ static int cxl_parse_cxims(union acpi_subtable_headers *header, void *arg,
struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
struct device *dev = ctx->dev;
struct cxl_cxims_data *cximsd;
unsigned int hbig, nr_maps;
int rc;
unsigned int nr_maps;
int hbig, rc;
rc = eig_to_granularity(cxims->hbig, &hbig);
if (rc)
@ -160,7 +160,7 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
struct acpi_cedt_cfmws *cfmws)
{
int rc, expected_len;
unsigned int ways;
int ways;
if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO &&
cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_XOR) {
@ -405,7 +405,7 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
struct cxl_cxims_context cxims_ctx;
struct device *dev = ctx->dev;
struct cxl_decoder *cxld;
unsigned int ways, i, ig;
int ways, i, ig;
int rc;
rc = cxl_acpi_cfmws_verify(dev, cfmws);
@ -464,7 +464,7 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
if (rc < 0)
return rc;
if (!cxlrd->platform_data) {
dev_err(dev, "No CXIMS for HBIG %u\n", ig);
dev_err(dev, "No CXIMS for HBIG %d\n", ig);
return -EINVAL;
}
}

View File

@ -423,6 +423,7 @@ static void *cxlctl_get_supported_features(struct cxl_features_state *cxlfs,
rpc_out->size = struct_size(feat_out, ents, requested);
feat_out = &rpc_out->get_sup_feats_out;
feat_out->num_entries = cpu_to_le16(requested);
for (i = start, pos = &feat_out->ents[0];
i < cxlfs->entries->num_features; i++, pos++) {
@ -444,7 +445,6 @@ static void *cxlctl_get_supported_features(struct cxl_features_state *cxlfs,
}
}
feat_out->num_entries = cpu_to_le16(requested);
feat_out->supported_feats = cpu_to_le16(cxlfs->entries->num_features);
rpc_out->retval = CXL_MBOX_CMD_RC_SUCCESS;
*out_len = out_size;

View File

@ -8,6 +8,10 @@
#include <cxlpci.h>
#include "trace.h"
/* Check that UCE header definition is maintained to keep ABI intact */
static_assert(CXL_HEADERLOG_TRACE_SIZE_U32 == 128,
"rasdaemon ABI requires exactly 128 u32s");
static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
struct cxl_ras_capability_regs ras_cap)
{
@ -19,6 +23,7 @@ static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
struct cxl_ras_capability_regs ras_cap)
{
u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;
u32 fe;
@ -28,8 +33,8 @@ static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
else
fe = status;
trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe,
ras_cap.header_log);
memcpy(hl, ras_cap.header_log, CXL_HEADERLOG_SIZE);
trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe, hl);
}
static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd,
@ -44,6 +49,7 @@ static void
cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd,
struct cxl_ras_capability_regs ras_cap)
{
u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;
u32 fe;
@ -53,8 +59,15 @@ cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd,
else
fe = status;
trace_cxl_aer_uncorrectable_error(cxlmd, status, fe,
ras_cap.header_log);
/*
* ras_cap.header_log[] holds CXL_HEADERLOG_SIZE_U32 (16) hardware
* dwords. Copy them into the front of a zero-filled
* CXL_HEADERLOG_TRACE_SIZE_U32 (128) u32 staging buffer so the trace
* event memcpy sees a full 512-byte source and the userspace ABI
* (rasdaemon) is preserved.
*/
memcpy(hl, ras_cap.header_log, CXL_HEADERLOG_SIZE);
trace_cxl_aer_uncorrectable_error(cxlmd, status, fe, hl);
}
static int match_memdev_by_parent(struct device *dev, const void *uport)
@ -204,12 +217,12 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
{
void __iomem *addr;
u32 *log_addr;
int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32);
int i;
addr = ras_base + CXL_RAS_HEADER_LOG_OFFSET;
log_addr = log;
for (i = 0; i < log_u32_size; i++) {
for (i = 0; i < CXL_HEADERLOG_SIZE_U32; i++) {
*log_addr = readl(addr);
log_addr++;
addr += sizeof(u32);
@ -222,7 +235,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
*/
bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
{
u32 hl[CXL_HEADERLOG_SIZE_U32];
u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
void __iomem *addr;
u32 status;
u32 fe;

View File

@ -1224,8 +1224,6 @@ static int cxl_port_attach_region(struct cxl_port *port,
nr_targets_inc = true;
}
} else {
struct cxl_decoder *cxld;
cxld = cxl_port_pick_region_decoder(port, cxled, cxlr);
if (!cxld) {
dev_dbg(&cxlr->dev, "%s: no decoder available\n",
@ -1848,8 +1846,21 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr,
* this means that userspace can view devices in the wrong position
* before the region activates, and must be careful to understand when
* it might be racing region autodiscovery.
*
* The endpoint decoder will be recorded into the first free slot of
* the target array.
*/
pos = p->nr_targets;
for (pos = 0; pos < p->interleave_ways; pos++) {
if (!p->targets[pos])
break;
}
if (pos == p->interleave_ways) {
dev_err(&cxlr->dev, "%s: unable to find a free target slot\n",
dev_name(&cxled->cxld.dev));
return -ENXIO;
}
p->targets[pos] = cxled;
cxled->pos = pos;
cxled->state = CXL_DECODER_STATE_AUTO_STAGED;
@ -2011,8 +2022,9 @@ static int cxl_region_sort_targets(struct cxl_region *cxlr)
cxled->pos = cxl_calc_interleave_pos(cxled, &cxlr->hpa_range);
/*
* Record that sorting failed, but still continue to calc
* cxled->pos so that follow-on code paths can reliably
* do p->targets[cxled->pos] to self-reference their entry.
* cxled->pos so that cxl_calc_interleave_pos() emits its
* dev_dbg() for every member. which is useful for auto
* discovery debug.
*/
if (cxled->pos < 0)
rc = -ENXIO;
@ -2189,31 +2201,43 @@ static int cxl_region_attach(struct cxl_region *cxlr,
* will fail when presented as CXL_REGION_F_AUTO.
*/
for (int i = 0; i < p->nr_targets; i++) {
struct cxl_endpoint_decoder *cxled = p->targets[i];
struct cxl_endpoint_decoder *target = p->targets[i];
int test_pos;
test_pos = cxl_calc_interleave_pos(cxled, &cxlr->hpa_range);
dev_dbg(&cxled->cxld.dev,
"Test cxl_calc_interleave_pos(): %s test_pos:%d cxled->pos:%d\n",
(test_pos == cxled->pos) ? "success" : "fail",
test_pos, cxled->pos);
test_pos = cxl_calc_interleave_pos(target, &cxlr->hpa_range);
dev_dbg(&target->cxld.dev,
"Test cxl_calc_interleave_pos(): %s test_pos:%d target->pos:%d\n",
(test_pos == target->pos) ? "success" : "fail",
test_pos, target->pos);
}
return 0;
}
static int cxl_region_by_target(struct device *dev, const void *data)
static int cxl_region_remove_target(struct device *dev, void *data)
{
const struct cxl_endpoint_decoder *cxled = data;
struct cxl_endpoint_decoder *cxled = data;
struct cxl_region_params *p;
struct cxl_region *cxlr;
int i;
if (!is_cxl_region(dev))
return 0;
cxlr = to_cxl_region(dev);
p = &cxlr->params;
return p->targets[cxled->pos] == cxled;
for (i = 0; i < p->interleave_ways; i++) {
if (p->targets[i] == cxled) {
p->nr_targets--;
cxled->state = CXL_DECODER_STATE_AUTO;
cxled->pos = -1;
p->targets[i] = NULL;
return 1;
}
}
return 0;
}
/*
@ -2222,25 +2246,10 @@ static int cxl_region_by_target(struct device *dev, const void *data)
*/
static void cxl_cancel_auto_attach(struct cxl_endpoint_decoder *cxled)
{
struct cxl_region_params *p;
struct cxl_region *cxlr;
int pos = cxled->pos;
if (cxled->state != CXL_DECODER_STATE_AUTO_STAGED)
return;
struct device *dev __free(put_device) =
bus_find_device(&cxl_bus_type, NULL, cxled, cxl_region_by_target);
if (!dev)
return;
cxlr = to_cxl_region(dev);
p = &cxlr->params;
p->nr_targets--;
cxled->state = CXL_DECODER_STATE_AUTO;
cxled->pos = -1;
p->targets[pos] = NULL;
bus_for_each_dev(&cxl_bus_type, NULL, cxled, cxl_region_remove_target);
}
static struct cxl_region *
@ -3060,7 +3069,7 @@ int cxl_validate_translation_params(u8 eiw, u16 eig, int pos)
return -EINVAL;
}
if (pos < 0 || pos >= ways) {
pr_debug("%s: invalid pos=%d for ways=%u\n", __func__, pos,
pr_debug("%s: invalid pos=%d for ways=%d\n", __func__, pos,
ways);
return -EINVAL;
}
@ -3106,7 +3115,7 @@ EXPORT_SYMBOL_FOR_MODULES(cxl_calculate_dpa_offset, "cxl_translate");
int cxl_calculate_position(u64 hpa_offset, u8 eiw, u16 eig)
{
unsigned int ways = 0;
int ways = 0;
u64 shifted, rem;
int pos, ret;
@ -3714,6 +3723,9 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
int rc, part = READ_ONCE(cxled->part);
struct cxl_region *cxlr;
if (part < 0)
return ERR_PTR(-EBUSY);
do {
cxlr = __create_region(cxlrd, cxlds->part[part].mode,
atomic_read(&cxlrd->region_id),

View File

@ -56,7 +56,7 @@ TRACE_EVENT(cxl_port_aer_uncorrectable_error,
__string(host, dev_name(dev->parent))
__field(u32, status)
__field(u32, first_error)
__array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
__array(u32, header_log, CXL_HEADERLOG_TRACE_SIZE_U32)
),
TP_fast_assign(
__assign_str(device);
@ -64,10 +64,14 @@ TRACE_EVENT(cxl_port_aer_uncorrectable_error,
__entry->status = status;
__entry->first_error = fe;
/*
* Embed the 512B headerlog data for user app retrieval and
* parsing, but no need to print this in the trace buffer.
* Embed headerlog data for user app retrieval and parsing,
* but no need to print in the trace buffer. Only
* CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data;
* the remaining entries preserve the 512-byte ABI layout
* rasdaemon depends on and are zero-filled by the caller.
*/
memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
memcpy(__entry->header_log, hl,
CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32));
),
TP_printk("device=%s host=%s status: '%s' first_error: '%s'",
__get_str(device), __get_str(host),
@ -85,7 +89,7 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
__field(u64, serial)
__field(u32, status)
__field(u32, first_error)
__array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
__array(u32, header_log, CXL_HEADERLOG_TRACE_SIZE_U32)
),
TP_fast_assign(
__assign_str(memdev);
@ -94,10 +98,14 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
__entry->status = status;
__entry->first_error = fe;
/*
* Embed the 512B headerlog data for user app retrieval and
* parsing, but no need to print this in the trace buffer.
* Embed headerlog data for user app retrieval and parsing,
* but no need to print in the trace buffer. Only
* CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data;
* the remaining entries preserve the 512-byte ABI layout
* rasdaemon depends on and are zero-filled by the caller.
*/
memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
memcpy(__entry->header_log, hl,
CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32));
),
TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'",
__get_str(memdev), __get_str(host), __entry->serial,

View File

@ -91,7 +91,7 @@ static inline int cxl_hdm_decoder_count(u32 cap_hdr)
}
/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
static inline int eig_to_granularity(u16 eig, unsigned int *granularity)
static inline int eig_to_granularity(u16 eig, int *granularity)
{
if (eig > CXL_DECODER_MAX_ENCODED_IG)
return -EINVAL;
@ -100,7 +100,7 @@ static inline int eig_to_granularity(u16 eig, unsigned int *granularity)
}
/* Encode defined in CXL ECN "3, 6, 12 and 16-way memory Interleaving" */
static inline int eiw_to_ways(u8 eiw, unsigned int *ways)
static inline int eiw_to_ways(u8 eiw, int *ways)
{
switch (eiw) {
case 0 ... 4:
@ -118,6 +118,7 @@ static inline int eiw_to_ways(u8 eiw, unsigned int *ways)
static inline int granularity_to_eig(int granularity, u16 *eig)
{
*eig = 0;
if (granularity > SZ_16K || granularity < CXL_DECODER_MIN_GRANULARITY ||
!is_power_of_2(granularity))
return -EINVAL;
@ -127,6 +128,7 @@ static inline int granularity_to_eig(int granularity, u16 *eig)
static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
{
*eiw = 0;
if (ways > 16)
return -EINVAL;
if (is_power_of_2(ways)) {
@ -158,8 +160,18 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
#define CXL_RAS_CAP_CONTROL_FE_MASK GENMASK(5, 0)
#define CXL_RAS_HEADER_LOG_OFFSET 0x18
#define CXL_RAS_CAPABILITY_LENGTH 0x58
#define CXL_HEADERLOG_SIZE SZ_512
#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32)
#define CXL_HEADERLOG_SIZE SZ_64
#define CXL_HEADERLOG_SIZE_U32 (CXL_HEADERLOG_SIZE / sizeof(u32))
/*
* The RAS UCE trace event header array was originally sized at SZ_512/sizeof(u32)
* = 128 u32s due to a bug. Userspace tools (rasdaemon) have grown a dependency
* on that 512-byte layout. Keep the trace array at 128 u32s to preserve the
* ABI; only CXL_HEADERLOG_SIZE_U32 (16) dwords are valid hardware data, the
* remainder are zero-filled.
*/
#define CXL_HEADERLOG_TRACE_SIZE SZ_512
#define CXL_HEADERLOG_TRACE_SIZE_U32 (CXL_HEADERLOG_TRACE_SIZE / sizeof(u32))
/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
#define CXLDEV_CAP_ARRAY_OFFSET 0x0

View File

@ -48,6 +48,11 @@ static int cxl_mem_dpa_show(struct seq_file *file, void *data)
static int cxl_debugfs_poison_inject(void *data, u64 dpa)
{
struct cxl_memdev *cxlmd = data;
int rc;
ACQUIRE(device_intr, devlock)(&cxlmd->dev);
if ((rc = ACQUIRE_ERR(device_intr, &devlock)))
return rc;
return cxl_inject_poison(cxlmd, dpa);
}
@ -58,6 +63,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(cxl_poison_inject_fops, NULL,
static int cxl_debugfs_poison_clear(void *data, u64 dpa)
{
struct cxl_memdev *cxlmd = data;
int rc;
ACQUIRE(device_intr, devlock)(&cxlmd->dev);
if ((rc = ACQUIRE_ERR(device_intr, &devlock)))
return rc;
return cxl_clear_poison(cxlmd, dpa);
}

View File

@ -18,7 +18,7 @@
* firmware) are managed in this drivers context. Each driver instance
* is responsible for tearing down the driver context of immediate
* descendant ports. The locking for this is validated by
* CONFIG_PROVE_CXL_LOCKING.
* CONFIG_PROVE_LOCKING.
*
* The primary service this driver provides is presenting APIs to other
* drivers to utilize the decoders, and indicating to userspace (via bind

View File

@ -318,7 +318,7 @@ static struct {
.restrictions = ACPI_CEDT_CFMWS_RESTRICT_HOSTONLYMEM |
ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
.qtg_id = FAKE_QTG_ID,
.window_size = SZ_256M,
.window_size = SZ_256M > PMD_SIZE ? SZ_256M : PMD_SIZE,
},
.target = { 3 },
},
@ -433,12 +433,16 @@ static void depopulate_all_mock_resources(void)
static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)
{
struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL);
struct genpool_data_align data = {
.align = align,
};
unsigned long phys;
struct cxl_mock_res *res __free(kfree) = kzalloc(sizeof(*res),
GFP_KERNEL);
if (!res)
return NULL;
INIT_LIST_HEAD(&res->list);
phys = gen_pool_alloc_algo(cxl_mock_pool, size,
gen_pool_first_fit_align, &data);
@ -453,7 +457,7 @@ static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)
list_add(&res->list, &mock_res);
mutex_unlock(&mock_res_lock);
return res;
return no_free_ptr(res);
}
/* Only update CFMWS0 as this is used by the auto region. */
@ -495,9 +499,12 @@ static int populate_cedt(void)
for (i = cfmws_start; i <= cfmws_end; i++) {
struct acpi_cedt_cfmws *window = mock_cfmws[i];
int align = SZ_256M;
cfmws_elc_update(window, i);
res = alloc_mock_res(window->window_size, SZ_256M);
if (window->restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE)
align = max_t(int, SZ_256M, PMD_SIZE);
res = alloc_mock_res(window->window_size, align);
if (!res)
return -ENOMEM;
window->base_hpa = res->range.start;
@ -1181,15 +1188,11 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
cxlsd = to_cxl_switch_decoder(dev);
if (i == 0) {
/* put cxl_mem.4 second in the decode order */
if (pdev->id == 4) {
cxlsd->target[1] = dport;
if (pdev->id == 4)
cxlsd->cxld.target_map[1] = dport->port_id;
} else {
cxlsd->target[0] = dport;
else
cxlsd->cxld.target_map[0] = dport->port_id;
}
} else {
cxlsd->target[0] = dport;
cxlsd->cxld.target_map[0] = dport->port_id;
}
cxld = &cxlsd->cxld;
@ -1212,6 +1215,16 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
cxld->commit = mock_decoder_commit;
cxld->reset = mock_decoder_reset;
/*
* Only target_map[] is programmed above, mimicking
* firmware. On real hardware target[] is populated as
* dports enumerate, via update_decoder_targets(). The
* mock's dports are already bound by now, so fire that
* resolution explicitly here rather than stamping
* target[] directly.
*/
cxl_port_update_decoder_targets(iter, dport);
cxld_registry_update(cxld);
put_device(dev);
}
@ -1819,6 +1832,12 @@ static __init int cxl_test_init(void)
int rc, i;
struct range mappable;
if (!IS_ALIGNED(mock_auto_region_size, PMD_SIZE)) {
pr_err_once("mock_auto_region_size %d must be PMD-aligned\n",
mock_auto_region_size);
return -EINVAL;
}
cxl_acpi_test();
cxl_core_test();
cxl_mem_test();
@ -1951,7 +1970,7 @@ static __init int cxl_test_init(void)
err_mem:
cxl_mem_exit();
err_root:
platform_device_put(cxl_acpi);
platform_device_unregister(cxl_acpi);
err_rch:
cxl_rch_topo_exit();
err_single:

View File

@ -236,8 +236,8 @@ static int setup_xor_mapping(void)
if (!cximsd)
return -ENOMEM;
memcpy(cximsd->xormaps, xormaps, nr_maps * sizeof(*cximsd->xormaps));
cximsd->nr_maps = nr_maps;
memcpy(cximsd->xormaps, xormaps, nr_maps * sizeof(*cximsd->xormaps));
return 0;
}

View File

@ -312,12 +312,17 @@ static int mock_get_event(struct device *dev, struct cxl_mbox_cmd *cmd)
static int mock_clear_event(struct device *dev, struct cxl_mbox_cmd *cmd)
{
struct cxl_mbox_clear_event_payload *pl = cmd->payload_in;
struct cxl_mbox_clear_event_payload *pl;
struct mock_event_log *log;
u8 log_type = pl->event_log;
u8 log_type;
u16 handle;
int nr;
if (cmd->size_in < sizeof(*pl))
return -EINVAL;
pl = cmd->payload_in;
log_type = pl->event_log;
if (log_type >= CXL_EVENT_TYPE_MAX)
return -EINVAL;
@ -574,14 +579,19 @@ static int mock_gsl(struct cxl_mbox_cmd *cmd)
static int mock_get_log(struct cxl_memdev_state *mds, struct cxl_mbox_cmd *cmd)
{
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
struct cxl_mbox_get_log *gl = cmd->payload_in;
u32 offset = le32_to_cpu(gl->offset);
u32 length = le32_to_cpu(gl->length);
uuid_t uuid = DEFINE_CXL_CEL_UUID;
struct cxl_mbox_get_log *gl;
void *data = &mock_cel;
u32 offset;
u32 length;
if (cmd->size_in < sizeof(*gl))
return -EINVAL;
gl = cmd->payload_in;
offset = le32_to_cpu(gl->offset);
length = le32_to_cpu(gl->length);
if (length > cxl_mbox->payload_size)
return -EINVAL;
if (offset + length > sizeof(mock_cel))
@ -1053,7 +1063,7 @@ static int mock_get_lsa(struct cxl_mockmem_data *mdata,
return -EINVAL;
offset = le32_to_cpu(get_lsa->offset);
length = le32_to_cpu(get_lsa->length);
if (offset + length > LSA_SIZE)
if (offset > LSA_SIZE || length > LSA_SIZE - offset)
return -EINVAL;
if (length > cmd->size_out)
return -EINVAL;
@ -1073,7 +1083,7 @@ static int mock_set_lsa(struct cxl_mockmem_data *mdata,
return -EINVAL;
offset = le32_to_cpu(set_lsa->offset);
length = cmd->size_in - sizeof(*set_lsa);
if (offset + length > LSA_SIZE)
if (offset > LSA_SIZE || length > LSA_SIZE - offset)
return -EINVAL;
memcpy(lsa + offset, &set_lsa->data[0], length);
@ -1336,10 +1346,14 @@ static int mock_fw_info(struct cxl_mockmem_data *mdata,
static int mock_transfer_fw(struct cxl_mockmem_data *mdata,
struct cxl_mbox_cmd *cmd)
{
struct cxl_mbox_transfer_fw *transfer = cmd->payload_in;
struct cxl_mbox_transfer_fw *transfer;
void *fw = mdata->fw;
size_t offset, length;
if (cmd->size_in < sizeof(*transfer))
return -EINVAL;
transfer = cmd->payload_in;
offset = le32_to_cpu(transfer->offset) * CXL_FW_TRANSFER_ALIGNMENT;
length = cmd->size_in - sizeof(*transfer);
if (offset + length > FW_SIZE)
@ -1415,11 +1429,18 @@ static int mock_get_test_feature(struct cxl_mockmem_data *mdata,
struct cxl_mbox_cmd *cmd)
{
struct vendor_test_feat *output = cmd->payload_out;
struct cxl_mbox_get_feat_in *input = cmd->payload_in;
u16 offset = le16_to_cpu(input->offset);
u16 count = le16_to_cpu(input->count);
struct cxl_mbox_get_feat_in *input;
u16 offset;
u16 count;
u8 *ptr;
if (cmd->size_in < sizeof(*input))
return -EINVAL;
input = cmd->payload_in;
offset = le16_to_cpu(input->offset);
count = le16_to_cpu(input->count);
if (offset > sizeof(*output)) {
cmd->return_code = CXL_MBOX_CMD_RC_INPUT;
return -EINVAL;
@ -1703,7 +1724,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
return -ENOMEM;
dev_set_drvdata(dev, mdata);
mdata->lsa = vmalloc(LSA_SIZE);
mdata->lsa = vzalloc(LSA_SIZE);
if (!mdata->lsa)
return -ENOMEM;
mdata->fw = vmalloc(FW_SIZE);