diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 66 |
1 files changed, 34 insertions, 32 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c index 2602ea12971e..d9def01f276e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | |||
@@ -358,8 +358,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) | |||
358 | struct acpi_table_header *hdr; | 358 | struct acpi_table_header *hdr; |
359 | acpi_size tbl_size; | 359 | acpi_size tbl_size; |
360 | UEFI_ACPI_VFCT *vfct; | 360 | UEFI_ACPI_VFCT *vfct; |
361 | GOP_VBIOS_CONTENT *vbios; | 361 | unsigned offset; |
362 | VFCT_IMAGE_HEADER *vhdr; | ||
363 | 362 | ||
364 | if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) | 363 | if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) |
365 | return false; | 364 | return false; |
@@ -370,42 +369,45 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) | |||
370 | } | 369 | } |
371 | 370 | ||
372 | vfct = (UEFI_ACPI_VFCT *)hdr; | 371 | vfct = (UEFI_ACPI_VFCT *)hdr; |
373 | if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) { | 372 | offset = vfct->VBIOSImageOffset; |
374 | DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n"); | ||
375 | return false; | ||
376 | } | ||
377 | 373 | ||
378 | vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset); | 374 | while (offset < tbl_size) { |
379 | vhdr = &vbios->VbiosHeader; | 375 | GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset); |
380 | DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n", | 376 | VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader; |
381 | vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction, | ||
382 | vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength); | ||
383 | |||
384 | if (vhdr->PCIBus != adev->pdev->bus->number || | ||
385 | vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) || | ||
386 | vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn) || | ||
387 | vhdr->VendorID != adev->pdev->vendor || | ||
388 | vhdr->DeviceID != adev->pdev->device) { | ||
389 | DRM_INFO("ACPI VFCT table is not for this card\n"); | ||
390 | return false; | ||
391 | } | ||
392 | 377 | ||
393 | if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) { | 378 | offset += sizeof(VFCT_IMAGE_HEADER); |
394 | DRM_ERROR("ACPI VFCT image truncated\n"); | 379 | if (offset > tbl_size) { |
395 | return false; | 380 | DRM_ERROR("ACPI VFCT image header truncated\n"); |
396 | } | 381 | return false; |
382 | } | ||
397 | 383 | ||
398 | adev->bios = kmemdup(&vbios->VbiosContent, | 384 | offset += vhdr->ImageLength; |
399 | vhdr->ImageLength, | 385 | if (offset > tbl_size) { |
400 | GFP_KERNEL); | 386 | DRM_ERROR("ACPI VFCT image truncated\n"); |
387 | return false; | ||
388 | } | ||
401 | 389 | ||
402 | if (!check_atom_bios(adev->bios, vhdr->ImageLength)) { | 390 | if (vhdr->ImageLength && |
403 | kfree(adev->bios); | 391 | vhdr->PCIBus == adev->pdev->bus->number && |
404 | return false; | 392 | vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) && |
393 | vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) && | ||
394 | vhdr->VendorID == adev->pdev->vendor && | ||
395 | vhdr->DeviceID == adev->pdev->device) { | ||
396 | adev->bios = kmemdup(&vbios->VbiosContent, | ||
397 | vhdr->ImageLength, | ||
398 | GFP_KERNEL); | ||
399 | |||
400 | if (!check_atom_bios(adev->bios, vhdr->ImageLength)) { | ||
401 | kfree(adev->bios); | ||
402 | return false; | ||
403 | } | ||
404 | adev->bios_size = vhdr->ImageLength; | ||
405 | return true; | ||
406 | } | ||
405 | } | 407 | } |
406 | adev->bios_size = vhdr->ImageLength; | ||
407 | 408 | ||
408 | return true; | 409 | DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n"); |
410 | return false; | ||
409 | } | 411 | } |
410 | #else | 412 | #else |
411 | static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) | 413 | static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) |