aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c66
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
411static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) 413static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)