Commit 466b7d16 authored by Shanker Donthineni's avatar Shanker Donthineni Committed by Marc Zyngier

irqchip/gicv3-its: Don't allow devices whose ID is outside range

We are not checking whether the requested device identifier fits into
the device table memory or not. The function its_create_device()
assumes that enough memory has been allocated for whole DevID space
(reported by ITS_TYPER.Devbits) during the ITS probe() and continues
to initialize ITS hardware.

This assumption is not perfect, sometimes we reduce memory size either
because of its size crossing MAX_ORDER-1 or BASERn max size limit. The
MAPD command fails if 'Device ID' is outside of device table range.

Add a simple validation check to avoid MAPD failures since we are
not handling ITS command errors. This change also helps to return an
error -ENOMEM instead of success to caller.
Signed-off-by: default avatarShanker Donthineni <shankerd@codeaurora.org>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 8cb17b5e
...@@ -54,6 +54,16 @@ struct its_collection { ...@@ -54,6 +54,16 @@ struct its_collection {
u16 col_id; u16 col_id;
}; };
/*
* The ITS_BASER structure - contains memory information and cached
* value of BASER register configuration.
*/
struct its_baser {
void *base;
u64 val;
u32 order;
};
/* /*
* The ITS structure - contains most of the infrastructure, with the * The ITS structure - contains most of the infrastructure, with the
* top-level MSI domain, the command queue, the collections, and the * top-level MSI domain, the command queue, the collections, and the
...@@ -66,14 +76,12 @@ struct its_node { ...@@ -66,14 +76,12 @@ struct its_node {
unsigned long phys_base; unsigned long phys_base;
struct its_cmd_block *cmd_base; struct its_cmd_block *cmd_base;
struct its_cmd_block *cmd_write; struct its_cmd_block *cmd_write;
struct { struct its_baser tables[GITS_BASER_NR_REGS];
void *base;
u32 order;
} tables[GITS_BASER_NR_REGS];
struct its_collection *collections; struct its_collection *collections;
struct list_head its_device_list; struct list_head its_device_list;
u64 flags; u64 flags;
u32 ite_size; u32 ite_size;
u32 device_ids;
}; };
#define ITS_ITT_ALIGN SZ_256 #define ITS_ITT_ALIGN SZ_256
...@@ -838,6 +846,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) ...@@ -838,6 +846,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
ids = GITS_TYPER_DEVBITS(typer); ids = GITS_TYPER_DEVBITS(typer);
} }
its->device_ids = ids;
for (i = 0; i < GITS_BASER_NR_REGS; i++) { for (i = 0; i < GITS_BASER_NR_REGS; i++) {
u64 val = readq_relaxed(its->base + GITS_BASER + i * 8); u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
u64 type = GITS_BASER_TYPE(val); u64 type = GITS_BASER_TYPE(val);
...@@ -913,6 +923,7 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) ...@@ -913,6 +923,7 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
} }
val |= alloc_pages - 1; val |= alloc_pages - 1;
its->tables[i].val = val;
writeq_relaxed(val, its->base + GITS_BASER + i * 8); writeq_relaxed(val, its->base + GITS_BASER + i * 8);
tmp = readq_relaxed(its->base + GITS_BASER + i * 8); tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
...@@ -1138,9 +1149,22 @@ static struct its_device *its_find_device(struct its_node *its, u32 dev_id) ...@@ -1138,9 +1149,22 @@ static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
return its_dev; return its_dev;
} }
static struct its_baser *its_get_baser(struct its_node *its, u32 type)
{
int i;
for (i = 0; i < GITS_BASER_NR_REGS; i++) {
if (GITS_BASER_TYPE(its->tables[i].val) == type)
return &its->tables[i];
}
return NULL;
}
static struct its_device *its_create_device(struct its_node *its, u32 dev_id, static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
int nvecs) int nvecs)
{ {
struct its_baser *baser;
struct its_device *dev; struct its_device *dev;
unsigned long *lpi_map; unsigned long *lpi_map;
unsigned long flags; unsigned long flags;
...@@ -1151,6 +1175,16 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, ...@@ -1151,6 +1175,16 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
int nr_ites; int nr_ites;
int sz; int sz;
baser = its_get_baser(its, GITS_BASER_TYPE_DEVICE);
/* Don't allow 'dev_id' that exceeds single, flat table limit */
if (baser) {
if (dev_id >= (PAGE_ORDER_TO_SIZE(baser->order) /
GITS_BASER_ENTRY_SIZE(baser->val)))
return NULL;
} else if (ilog2(dev_id) >= its->device_ids)
return NULL;
dev = kzalloc(sizeof(*dev), GFP_KERNEL); dev = kzalloc(sizeof(*dev), GFP_KERNEL);
/* /*
* At least one bit of EventID is being used, hence a minimum * At least one bit of EventID is being used, hence a minimum
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment