diff options
| -rw-r--r-- | drivers/acpi/apei/apei-base.c | 61 |
1 files changed, 40 insertions, 21 deletions
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index e5d53b7ddc7e..1d3656f6919f 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c | |||
| @@ -558,33 +558,48 @@ void apei_resources_release(struct apei_resources *resources) | |||
| 558 | } | 558 | } |
| 559 | EXPORT_SYMBOL_GPL(apei_resources_release); | 559 | EXPORT_SYMBOL_GPL(apei_resources_release); |
| 560 | 560 | ||
| 561 | static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr) | 561 | static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr, |
| 562 | u32 *access_bit_width) | ||
| 562 | { | 563 | { |
| 563 | u32 width, space_id; | 564 | u32 bit_width, bit_offset, access_size_code, space_id; |
| 564 | 565 | ||
| 565 | width = reg->bit_width; | 566 | bit_width = reg->bit_width; |
| 567 | bit_offset = reg->bit_offset; | ||
| 568 | access_size_code = reg->access_width; | ||
| 566 | space_id = reg->space_id; | 569 | space_id = reg->space_id; |
| 567 | /* Handle possible alignment issues */ | 570 | /* Handle possible alignment issues */ |
| 568 | memcpy(paddr, ®->address, sizeof(*paddr)); | 571 | memcpy(paddr, ®->address, sizeof(*paddr)); |
| 569 | if (!*paddr) { | 572 | if (!*paddr) { |
| 570 | pr_warning(FW_BUG APEI_PFX | 573 | pr_warning(FW_BUG APEI_PFX |
| 571 | "Invalid physical address in GAR [0x%llx/%u/%u]\n", | 574 | "Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n", |
| 572 | *paddr, width, space_id); | 575 | *paddr, bit_width, bit_offset, access_size_code, |
| 576 | space_id); | ||
| 573 | return -EINVAL; | 577 | return -EINVAL; |
| 574 | } | 578 | } |
| 575 | 579 | ||
| 576 | if ((width != 8) && (width != 16) && (width != 32) && (width != 64)) { | 580 | if (access_size_code < 1 || access_size_code > 4) { |
| 577 | pr_warning(FW_BUG APEI_PFX | 581 | pr_warning(FW_BUG APEI_PFX |
| 578 | "Invalid bit width in GAR [0x%llx/%u/%u]\n", | 582 | "Invalid access size code in GAR [0x%llx/%u/%u/%u/%u]\n", |
| 579 | *paddr, width, space_id); | 583 | *paddr, bit_width, bit_offset, access_size_code, |
| 584 | space_id); | ||
| 585 | return -EINVAL; | ||
| 586 | } | ||
| 587 | *access_bit_width = 1UL << (access_size_code + 2); | ||
| 588 | |||
| 589 | if ((bit_width + bit_offset) > *access_bit_width) { | ||
| 590 | pr_warning(FW_BUG APEI_PFX | ||
| 591 | "Invalid bit width + offset in GAR [0x%llx/%u/%u/%u/%u]\n", | ||
| 592 | *paddr, bit_width, bit_offset, access_size_code, | ||
| 593 | space_id); | ||
| 580 | return -EINVAL; | 594 | return -EINVAL; |
| 581 | } | 595 | } |
| 582 | 596 | ||
| 583 | if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY && | 597 | if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY && |
| 584 | space_id != ACPI_ADR_SPACE_SYSTEM_IO) { | 598 | space_id != ACPI_ADR_SPACE_SYSTEM_IO) { |
| 585 | pr_warning(FW_BUG APEI_PFX | 599 | pr_warning(FW_BUG APEI_PFX |
| 586 | "Invalid address space type in GAR [0x%llx/%u/%u]\n", | 600 | "Invalid address space type in GAR [0x%llx/%u/%u/%u/%u]\n", |
| 587 | *paddr, width, space_id); | 601 | *paddr, bit_width, bit_offset, access_size_code, |
| 602 | space_id); | ||
| 588 | return -EINVAL; | 603 | return -EINVAL; |
| 589 | } | 604 | } |
| 590 | 605 | ||
| @@ -595,23 +610,25 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr) | |||
| 595 | int apei_read(u64 *val, struct acpi_generic_address *reg) | 610 | int apei_read(u64 *val, struct acpi_generic_address *reg) |
| 596 | { | 611 | { |
| 597 | int rc; | 612 | int rc; |
| 613 | u32 access_bit_width; | ||
| 598 | u64 address; | 614 | u64 address; |
| 599 | acpi_status status; | 615 | acpi_status status; |
| 600 | 616 | ||
| 601 | rc = apei_check_gar(reg, &address); | 617 | rc = apei_check_gar(reg, &address, &access_bit_width); |
| 602 | if (rc) | 618 | if (rc) |
| 603 | return rc; | 619 | return rc; |
| 604 | 620 | ||
| 605 | *val = 0; | 621 | *val = 0; |
| 606 | switch(reg->space_id) { | 622 | switch(reg->space_id) { |
| 607 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | 623 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: |
| 608 | status = acpi_os_read_memory64((acpi_physical_address) | 624 | status = acpi_os_read_memory64((acpi_physical_address) address, |
| 609 | address, val, reg->bit_width); | 625 | val, access_bit_width); |
| 610 | if (ACPI_FAILURE(status)) | 626 | if (ACPI_FAILURE(status)) |
| 611 | return -EIO; | 627 | return -EIO; |
| 612 | break; | 628 | break; |
| 613 | case ACPI_ADR_SPACE_SYSTEM_IO: | 629 | case ACPI_ADR_SPACE_SYSTEM_IO: |
| 614 | status = acpi_os_read_port(address, (u32 *)val, reg->bit_width); | 630 | status = acpi_os_read_port(address, (u32 *)val, |
| 631 | access_bit_width); | ||
| 615 | if (ACPI_FAILURE(status)) | 632 | if (ACPI_FAILURE(status)) |
| 616 | return -EIO; | 633 | return -EIO; |
| 617 | break; | 634 | break; |
| @@ -627,22 +644,23 @@ EXPORT_SYMBOL_GPL(apei_read); | |||
| 627 | int apei_write(u64 val, struct acpi_generic_address *reg) | 644 | int apei_write(u64 val, struct acpi_generic_address *reg) |
| 628 | { | 645 | { |
| 629 | int rc; | 646 | int rc; |
| 647 | u32 access_bit_width; | ||
| 630 | u64 address; | 648 | u64 address; |
| 631 | acpi_status status; | 649 | acpi_status status; |
| 632 | 650 | ||
| 633 | rc = apei_check_gar(reg, &address); | 651 | rc = apei_check_gar(reg, &address, &access_bit_width); |
| 634 | if (rc) | 652 | if (rc) |
| 635 | return rc; | 653 | return rc; |
| 636 | 654 | ||
| 637 | switch (reg->space_id) { | 655 | switch (reg->space_id) { |
| 638 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | 656 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: |
| 639 | status = acpi_os_write_memory64((acpi_physical_address) | 657 | status = acpi_os_write_memory64((acpi_physical_address) address, |
| 640 | address, val, reg->bit_width); | 658 | val, access_bit_width); |
| 641 | if (ACPI_FAILURE(status)) | 659 | if (ACPI_FAILURE(status)) |
| 642 | return -EIO; | 660 | return -EIO; |
| 643 | break; | 661 | break; |
| 644 | case ACPI_ADR_SPACE_SYSTEM_IO: | 662 | case ACPI_ADR_SPACE_SYSTEM_IO: |
| 645 | status = acpi_os_write_port(address, val, reg->bit_width); | 663 | status = acpi_os_write_port(address, val, access_bit_width); |
| 646 | if (ACPI_FAILURE(status)) | 664 | if (ACPI_FAILURE(status)) |
| 647 | return -EIO; | 665 | return -EIO; |
| 648 | break; | 666 | break; |
| @@ -661,23 +679,24 @@ static int collect_res_callback(struct apei_exec_context *ctx, | |||
| 661 | struct apei_resources *resources = data; | 679 | struct apei_resources *resources = data; |
| 662 | struct acpi_generic_address *reg = &entry->register_region; | 680 | struct acpi_generic_address *reg = &entry->register_region; |
| 663 | u8 ins = entry->instruction; | 681 | u8 ins = entry->instruction; |
| 682 | u32 access_bit_width; | ||
| 664 | u64 paddr; | 683 | u64 paddr; |
| 665 | int rc; | 684 | int rc; |
| 666 | 685 | ||
| 667 | if (!(ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)) | 686 | if (!(ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)) |
| 668 | return 0; | 687 | return 0; |
| 669 | 688 | ||
| 670 | rc = apei_check_gar(reg, &paddr); | 689 | rc = apei_check_gar(reg, &paddr, &access_bit_width); |
| 671 | if (rc) | 690 | if (rc) |
| 672 | return rc; | 691 | return rc; |
| 673 | 692 | ||
| 674 | switch (reg->space_id) { | 693 | switch (reg->space_id) { |
| 675 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | 694 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: |
| 676 | return apei_res_add(&resources->iomem, paddr, | 695 | return apei_res_add(&resources->iomem, paddr, |
| 677 | reg->bit_width / 8); | 696 | access_bit_width / 8); |
| 678 | case ACPI_ADR_SPACE_SYSTEM_IO: | 697 | case ACPI_ADR_SPACE_SYSTEM_IO: |
| 679 | return apei_res_add(&resources->ioport, paddr, | 698 | return apei_res_add(&resources->ioport, paddr, |
| 680 | reg->bit_width / 8); | 699 | access_bit_width / 8); |
| 681 | default: | 700 | default: |
| 682 | return -EINVAL; | 701 | return -EINVAL; |
| 683 | } | 702 | } |
