diff options
Diffstat (limited to 'drivers/acpi/nfit.c')
-rw-r--r-- | drivers/acpi/nfit.c | 67 |
1 files changed, 48 insertions, 19 deletions
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index f7dab53b352a..aa45d4802707 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c | |||
@@ -233,11 +233,12 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc, | |||
233 | struct nfit_table_prev *prev, | 233 | struct nfit_table_prev *prev, |
234 | struct acpi_nfit_system_address *spa) | 234 | struct acpi_nfit_system_address *spa) |
235 | { | 235 | { |
236 | size_t length = min_t(size_t, sizeof(*spa), spa->header.length); | ||
236 | struct device *dev = acpi_desc->dev; | 237 | struct device *dev = acpi_desc->dev; |
237 | struct nfit_spa *nfit_spa; | 238 | struct nfit_spa *nfit_spa; |
238 | 239 | ||
239 | list_for_each_entry(nfit_spa, &prev->spas, list) { | 240 | list_for_each_entry(nfit_spa, &prev->spas, list) { |
240 | if (memcmp(nfit_spa->spa, spa, sizeof(*spa)) == 0) { | 241 | if (memcmp(nfit_spa->spa, spa, length) == 0) { |
241 | list_move_tail(&nfit_spa->list, &acpi_desc->spas); | 242 | list_move_tail(&nfit_spa->list, &acpi_desc->spas); |
242 | return true; | 243 | return true; |
243 | } | 244 | } |
@@ -259,11 +260,12 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc, | |||
259 | struct nfit_table_prev *prev, | 260 | struct nfit_table_prev *prev, |
260 | struct acpi_nfit_memory_map *memdev) | 261 | struct acpi_nfit_memory_map *memdev) |
261 | { | 262 | { |
263 | size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length); | ||
262 | struct device *dev = acpi_desc->dev; | 264 | struct device *dev = acpi_desc->dev; |
263 | struct nfit_memdev *nfit_memdev; | 265 | struct nfit_memdev *nfit_memdev; |
264 | 266 | ||
265 | list_for_each_entry(nfit_memdev, &prev->memdevs, list) | 267 | list_for_each_entry(nfit_memdev, &prev->memdevs, list) |
266 | if (memcmp(nfit_memdev->memdev, memdev, sizeof(*memdev)) == 0) { | 268 | if (memcmp(nfit_memdev->memdev, memdev, length) == 0) { |
267 | list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs); | 269 | list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs); |
268 | return true; | 270 | return true; |
269 | } | 271 | } |
@@ -284,11 +286,12 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc, | |||
284 | struct nfit_table_prev *prev, | 286 | struct nfit_table_prev *prev, |
285 | struct acpi_nfit_control_region *dcr) | 287 | struct acpi_nfit_control_region *dcr) |
286 | { | 288 | { |
289 | size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length); | ||
287 | struct device *dev = acpi_desc->dev; | 290 | struct device *dev = acpi_desc->dev; |
288 | struct nfit_dcr *nfit_dcr; | 291 | struct nfit_dcr *nfit_dcr; |
289 | 292 | ||
290 | list_for_each_entry(nfit_dcr, &prev->dcrs, list) | 293 | list_for_each_entry(nfit_dcr, &prev->dcrs, list) |
291 | if (memcmp(nfit_dcr->dcr, dcr, sizeof(*dcr)) == 0) { | 294 | if (memcmp(nfit_dcr->dcr, dcr, length) == 0) { |
292 | list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs); | 295 | list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs); |
293 | return true; | 296 | return true; |
294 | } | 297 | } |
@@ -308,11 +311,12 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc, | |||
308 | struct nfit_table_prev *prev, | 311 | struct nfit_table_prev *prev, |
309 | struct acpi_nfit_data_region *bdw) | 312 | struct acpi_nfit_data_region *bdw) |
310 | { | 313 | { |
314 | size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length); | ||
311 | struct device *dev = acpi_desc->dev; | 315 | struct device *dev = acpi_desc->dev; |
312 | struct nfit_bdw *nfit_bdw; | 316 | struct nfit_bdw *nfit_bdw; |
313 | 317 | ||
314 | list_for_each_entry(nfit_bdw, &prev->bdws, list) | 318 | list_for_each_entry(nfit_bdw, &prev->bdws, list) |
315 | if (memcmp(nfit_bdw->bdw, bdw, sizeof(*bdw)) == 0) { | 319 | if (memcmp(nfit_bdw->bdw, bdw, length) == 0) { |
316 | list_move_tail(&nfit_bdw->list, &acpi_desc->bdws); | 320 | list_move_tail(&nfit_bdw->list, &acpi_desc->bdws); |
317 | return true; | 321 | return true; |
318 | } | 322 | } |
@@ -332,11 +336,12 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc, | |||
332 | struct nfit_table_prev *prev, | 336 | struct nfit_table_prev *prev, |
333 | struct acpi_nfit_interleave *idt) | 337 | struct acpi_nfit_interleave *idt) |
334 | { | 338 | { |
339 | size_t length = min_t(size_t, sizeof(*idt), idt->header.length); | ||
335 | struct device *dev = acpi_desc->dev; | 340 | struct device *dev = acpi_desc->dev; |
336 | struct nfit_idt *nfit_idt; | 341 | struct nfit_idt *nfit_idt; |
337 | 342 | ||
338 | list_for_each_entry(nfit_idt, &prev->idts, list) | 343 | list_for_each_entry(nfit_idt, &prev->idts, list) |
339 | if (memcmp(nfit_idt->idt, idt, sizeof(*idt)) == 0) { | 344 | if (memcmp(nfit_idt->idt, idt, length) == 0) { |
340 | list_move_tail(&nfit_idt->list, &acpi_desc->idts); | 345 | list_move_tail(&nfit_idt->list, &acpi_desc->idts); |
341 | return true; | 346 | return true; |
342 | } | 347 | } |
@@ -356,11 +361,12 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc, | |||
356 | struct nfit_table_prev *prev, | 361 | struct nfit_table_prev *prev, |
357 | struct acpi_nfit_flush_address *flush) | 362 | struct acpi_nfit_flush_address *flush) |
358 | { | 363 | { |
364 | size_t length = min_t(size_t, sizeof(*flush), flush->header.length); | ||
359 | struct device *dev = acpi_desc->dev; | 365 | struct device *dev = acpi_desc->dev; |
360 | struct nfit_flush *nfit_flush; | 366 | struct nfit_flush *nfit_flush; |
361 | 367 | ||
362 | list_for_each_entry(nfit_flush, &prev->flushes, list) | 368 | list_for_each_entry(nfit_flush, &prev->flushes, list) |
363 | if (memcmp(nfit_flush->flush, flush, sizeof(*flush)) == 0) { | 369 | if (memcmp(nfit_flush->flush, flush, length) == 0) { |
364 | list_move_tail(&nfit_flush->list, &acpi_desc->flushes); | 370 | list_move_tail(&nfit_flush->list, &acpi_desc->flushes); |
365 | return true; | 371 | return true; |
366 | } | 372 | } |
@@ -655,7 +661,7 @@ static ssize_t revision_show(struct device *dev, | |||
655 | struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); | 661 | struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); |
656 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); | 662 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); |
657 | 663 | ||
658 | return sprintf(buf, "%d\n", acpi_desc->nfit->header.revision); | 664 | return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision); |
659 | } | 665 | } |
660 | static DEVICE_ATTR_RO(revision); | 666 | static DEVICE_ATTR_RO(revision); |
661 | 667 | ||
@@ -1652,7 +1658,6 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz) | |||
1652 | 1658 | ||
1653 | data = (u8 *) acpi_desc->nfit; | 1659 | data = (u8 *) acpi_desc->nfit; |
1654 | end = data + sz; | 1660 | end = data + sz; |
1655 | data += sizeof(struct acpi_table_nfit); | ||
1656 | while (!IS_ERR_OR_NULL(data)) | 1661 | while (!IS_ERR_OR_NULL(data)) |
1657 | data = add_table(acpi_desc, &prev, data, end); | 1662 | data = add_table(acpi_desc, &prev, data, end); |
1658 | 1663 | ||
@@ -1748,13 +1753,29 @@ static int acpi_nfit_add(struct acpi_device *adev) | |||
1748 | return PTR_ERR(acpi_desc); | 1753 | return PTR_ERR(acpi_desc); |
1749 | } | 1754 | } |
1750 | 1755 | ||
1751 | acpi_desc->nfit = (struct acpi_table_nfit *) tbl; | 1756 | /* |
1757 | * Save the acpi header for later and then skip it, | ||
1758 | * making nfit point to the first nfit table header. | ||
1759 | */ | ||
1760 | acpi_desc->acpi_header = *tbl; | ||
1761 | acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit); | ||
1762 | sz -= sizeof(struct acpi_table_nfit); | ||
1752 | 1763 | ||
1753 | /* Evaluate _FIT and override with that if present */ | 1764 | /* Evaluate _FIT and override with that if present */ |
1754 | status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf); | 1765 | status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf); |
1755 | if (ACPI_SUCCESS(status) && buf.length > 0) { | 1766 | if (ACPI_SUCCESS(status) && buf.length > 0) { |
1756 | acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer; | 1767 | union acpi_object *obj; |
1757 | sz = buf.length; | 1768 | /* |
1769 | * Adjust for the acpi_object header of the _FIT | ||
1770 | */ | ||
1771 | obj = buf.pointer; | ||
1772 | if (obj->type == ACPI_TYPE_BUFFER) { | ||
1773 | acpi_desc->nfit = | ||
1774 | (struct acpi_nfit_header *)obj->buffer.pointer; | ||
1775 | sz = obj->buffer.length; | ||
1776 | } else | ||
1777 | dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n", | ||
1778 | __func__, (int) obj->type); | ||
1758 | } | 1779 | } |
1759 | 1780 | ||
1760 | rc = acpi_nfit_init(acpi_desc, sz); | 1781 | rc = acpi_nfit_init(acpi_desc, sz); |
@@ -1777,7 +1798,8 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) | |||
1777 | { | 1798 | { |
1778 | struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev); | 1799 | struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev); |
1779 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; | 1800 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; |
1780 | struct acpi_table_nfit *nfit_saved; | 1801 | struct acpi_nfit_header *nfit_saved; |
1802 | union acpi_object *obj; | ||
1781 | struct device *dev = &adev->dev; | 1803 | struct device *dev = &adev->dev; |
1782 | acpi_status status; | 1804 | acpi_status status; |
1783 | int ret; | 1805 | int ret; |
@@ -1788,7 +1810,7 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) | |||
1788 | if (!dev->driver) { | 1810 | if (!dev->driver) { |
1789 | /* dev->driver may be null if we're being removed */ | 1811 | /* dev->driver may be null if we're being removed */ |
1790 | dev_dbg(dev, "%s: no driver found for dev\n", __func__); | 1812 | dev_dbg(dev, "%s: no driver found for dev\n", __func__); |
1791 | return; | 1813 | goto out_unlock; |
1792 | } | 1814 | } |
1793 | 1815 | ||
1794 | if (!acpi_desc) { | 1816 | if (!acpi_desc) { |
@@ -1808,12 +1830,19 @@ static void acpi_nfit_notify(struct acpi_device *adev, u32 event) | |||
1808 | } | 1830 | } |
1809 | 1831 | ||
1810 | nfit_saved = acpi_desc->nfit; | 1832 | nfit_saved = acpi_desc->nfit; |
1811 | acpi_desc->nfit = (struct acpi_table_nfit *)buf.pointer; | 1833 | obj = buf.pointer; |
1812 | ret = acpi_nfit_init(acpi_desc, buf.length); | 1834 | if (obj->type == ACPI_TYPE_BUFFER) { |
1813 | if (!ret) { | 1835 | acpi_desc->nfit = |
1814 | /* Merge failed, restore old nfit, and exit */ | 1836 | (struct acpi_nfit_header *)obj->buffer.pointer; |
1815 | acpi_desc->nfit = nfit_saved; | 1837 | ret = acpi_nfit_init(acpi_desc, obj->buffer.length); |
1816 | dev_err(dev, "failed to merge updated NFIT\n"); | 1838 | if (ret) { |
1839 | /* Merge failed, restore old nfit, and exit */ | ||
1840 | acpi_desc->nfit = nfit_saved; | ||
1841 | dev_err(dev, "failed to merge updated NFIT\n"); | ||
1842 | } | ||
1843 | } else { | ||
1844 | /* Bad _FIT, restore old nfit */ | ||
1845 | dev_err(dev, "Invalid _FIT\n"); | ||
1817 | } | 1846 | } |
1818 | kfree(buf.pointer); | 1847 | kfree(buf.pointer); |
1819 | 1848 | ||