|
@@ -233,11 +233,12 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc,
|
|
|
struct nfit_table_prev *prev,
|
|
|
struct acpi_nfit_system_address *spa)
|
|
|
{
|
|
|
+ size_t length = min_t(size_t, sizeof(*spa), spa->header.length);
|
|
|
struct device *dev = acpi_desc->dev;
|
|
|
struct nfit_spa *nfit_spa;
|
|
|
|
|
|
list_for_each_entry(nfit_spa, &prev->spas, list) {
|
|
|
- if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) {
|
|
|
+ if (memcmp(nfit_spa->spa, spa, length) == 0) {
|
|
|
list_move_tail(&nfit_spa->list, &acpi_desc->spas);
|
|
|
return true;
|
|
|
}
|
|
@@ -259,11 +260,12 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
|
|
|
struct nfit_table_prev *prev,
|
|
|
struct acpi_nfit_memory_map *memdev)
|
|
|
{
|
|
|
+ size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length);
|
|
|
struct device *dev = acpi_desc->dev;
|
|
|
struct nfit_memdev *nfit_memdev;
|
|
|
|
|
|
list_for_each_entry(nfit_memdev, &prev->memdevs, list)
|
|
|
- if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) {
|
|
|
+ if (memcmp(nfit_memdev->memdev, memdev, length) == 0) {
|
|
|
list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs);
|
|
|
return true;
|
|
|
}
|
|
@@ -284,11 +286,12 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
|
|
|
struct nfit_table_prev *prev,
|
|
|
struct acpi_nfit_control_region *dcr)
|
|
|
{
|
|
|
+ size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length);
|
|
|
struct device *dev = acpi_desc->dev;
|
|
|
struct nfit_dcr *nfit_dcr;
|
|
|
|
|
|
list_for_each_entry(nfit_dcr, &prev->dcrs, list)
|
|
|
- if (memcmp(nfit_dcr->dcr, dcr, sizeof(*dcr)) == 0) {
|
|
|
+ if (memcmp(nfit_dcr->dcr, dcr, length) == 0) {
|
|
|
list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs);
|
|
|
return true;
|
|
|
}
|
|
@@ -308,11 +311,12 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
|
|
|
struct nfit_table_prev *prev,
|
|
|
struct acpi_nfit_data_region *bdw)
|
|
|
{
|
|
|
+ size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length);
|
|
|
struct device *dev = acpi_desc->dev;
|
|
|
struct nfit_bdw *nfit_bdw;
|
|
|
|
|
|
list_for_each_entry(nfit_bdw, &prev->bdws, list)
|
|
|
- if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) {
|
|
|
+ if (memcmp(nfit_bdw->bdw, bdw, length) == 0) {
|
|
|
list_move_tail(&nfit_bdw->list, &acpi_desc->bdws);
|
|
|
return true;
|
|
|
}
|
|
@@ -332,11 +336,12 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc,
|
|
|
struct nfit_table_prev *prev,
|
|
|
struct acpi_nfit_interleave *idt)
|
|
|
{
|
|
|
+ size_t length = min_t(size_t, sizeof(*idt), idt->header.length);
|
|
|
struct device *dev = acpi_desc->dev;
|
|
|
struct nfit_idt *nfit_idt;
|
|
|
|
|
|
list_for_each_entry(nfit_idt, &prev->idts, list)
|
|
|
- if (memcmp(nfit_idt->idt, idt, sizeof(*idt)) == 0) {
|
|
|
+ if (memcmp(nfit_idt->idt, idt, length) == 0) {
|
|
|
list_move_tail(&nfit_idt->list, &acpi_desc->idts);
|
|
|
return true;
|
|
|
}
|
|
@@ -356,11 +361,12 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc,
|
|
|
struct nfit_table_prev *prev,
|
|
|
struct acpi_nfit_flush_address *flush)
|
|
|
{
|
|
|
+ size_t length = min_t(size_t, sizeof(*flush), flush->header.length);
|
|
|
struct device *dev = acpi_desc->dev;
|
|
|
struct nfit_flush *nfit_flush;
|
|
|
|
|
|
list_for_each_entry(nfit_flush, &prev->flushes, list)
|
|
|
- if (memcmp(nfit_flush->flush, flush, sizeof(*flush)) == 0) {
|
|
|
+ if (memcmp(nfit_flush->flush, flush, length) == 0) {
|
|
|
list_move_tail(&nfit_flush->list, &acpi_desc->flushes);
|
|
|
return true;
|
|
|
}
|
|
@@ -655,7 +661,7 @@ static ssize_t revision_show(struct device *dev,
|
|
|
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
|
|
|
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
|
|
|
|
|
|
- return sprintf(buf, "%d\n", acpi_desc->nfit->header.revision);
|
|
|
+ return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision);
|
|
|
}
|
|
|
static DEVICE_ATTR_RO(revision);
|
|
|
|
|
@@ -1652,7 +1658,6 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
|
|
|
|
|
|
data = (u8 *) acpi_desc->nfit;
|
|
|
end = data + sz;
|
|
|
- data += sizeof(struct acpi_table_nfit);
|
|
|
while (!IS_ERR_OR_NULL(data))
|
|
|
data = add_table(acpi_desc, &prev, data, end);
|
|
|
|
|
@@ -1748,13 +1753,29 @@ static int acpi_nfit_add(struct acpi_device *adev)
|
|
|
return PTR_ERR(acpi_desc);
|
|
|
}
|
|
|
|
|
|
- acpi_desc->nfit = (struct acpi_table_nfit *) tbl;
|
|
|
+ /*
|
|
|
+ * Save the acpi header for later and then skip it,
|
|
|
+ * making nfit point to the first nfit table header.
|
|
|
+ */
|
|
|
+ acpi_desc->acpi_header = *tbl;
|
|
|
+ acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit);
|
|
|
+ sz -= sizeof(struct acpi_table_nfit);
|
|
|
|
|
|
/* Evaluate _FIT and override with that if present */
|
|
|
status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
|
|
|
if (ACPI_SUCCESS(status) && buf.length > 0) {
|
|
|
- acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer;
|
|
|
- sz = buf.length;
|
|
|
+ union acpi_object *obj;
|
|
|
+ /*
|
|
|
+ * Adjust for the acpi_object header of the _FIT
|
|
|
+ */
|
|
|
+ obj = buf.pointer;
|
|
|
+ if (obj->type == ACPI_TYPE_BUFFER) {
|
|
|
+ acpi_desc->nfit =
|
|
|
+ (struct acpi_nfit_header *)obj->buffer.pointer;
|
|
|
+ sz = obj->buffer.length;
|
|
|
+ } else
|
|
|
+ dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n",
|
|
|
+ __func__, (int) obj->type);
|
|
|
}
|
|
|
|
|
|
rc = acpi_nfit_init(acpi_desc, sz);
|
|
@@ -1777,7 +1798,8 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
|
|
|
{
|
|
|
struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
|
|
|
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
|
- struct acpi_table_nfit *nfit_saved;
|
|
|
+ struct acpi_nfit_header *nfit_saved;
|
|
|
+ union acpi_object *obj;
|
|
|
struct device *dev = &adev->dev;
|
|
|
acpi_status status;
|
|
|
int ret;
|
|
@@ -1808,12 +1830,19 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
|
|
|
}
|
|
|
|
|
|
nfit_saved = acpi_desc->nfit;
|
|
|
- acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer;
|
|
|
- ret = acpi_nfit_init(acpi_desc, buf.length);
|
|
|
- if (!ret) {
|
|
|
- /* Merge failed, restore old nfit, and exit */
|
|
|
- acpi_desc->nfit = nfit_saved;
|
|
|
- dev_err(dev, "failed to merge updated NFIT\n");
|
|
|
+ obj = buf.pointer;
|
|
|
+ if (obj->type == ACPI_TYPE_BUFFER) {
|
|
|
+ acpi_desc->nfit =
|
|
|
+ (struct acpi_nfit_header *)obj->buffer.pointer;
|
|
|
+ ret = acpi_nfit_init(acpi_desc, obj->buffer.length);
|
|
|
+ if (ret) {
|
|
|
+ /* Merge failed, restore old nfit, and exit */
|
|
|
+ acpi_desc->nfit = nfit_saved;
|
|
|
+ dev_err(dev, "failed to merge updated NFIT\n");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Bad _FIT, restore old nfit */
|
|
|
+ dev_err(dev, "Invalid _FIT\n");
|
|
|
}
|
|
|
kfree(buf.pointer);
|
|
|
|