]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/amdgpu/vce1: Fix VCE 1 firmware size and offsets
authorTimur Kristóf <timur.kristof@gmail.com>
Wed, 13 May 2026 20:04:13 +0000 (22:04 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Jun 2026 15:54:50 +0000 (17:54 +0200)
[ Upstream commit 3e5a1d5bb2ff061e64c7992f8e5404dfd4c2d0f3 ]

The VCPU BO contains the actual FW at an offset, but
it was not calculated into the VCPU BO size.
Subtract this from the FW size to make sure there is
no out of bounds access.

Make sure the stack and data offsets are aligned to
the 32K TLB size.

Check that the FW microcode actually fits in the
space that is reserved for it.

Fixes: d4a640d4b9f3 ("drm/amdgpu/vce1: Implement VCE1 IP block (v2)")
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit c16fe59f622a080fc457a57b3e8f14c780699449)
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/amd/amdgpu/vce_v1_0.c

index 0b69773b718486551f5af7e3c60f045d2398e2ca..d63ff64943d58c6b4b22898e80fd23064edc3ee8 100644 (file)
 #include "oss/oss_1_0_d.h"
 #include "oss/oss_1_0_sh_mask.h"
 
+#define VCE_V1_0_ALIGNMENT     (32 * 1024)
 #define VCE_V1_0_FW_SIZE       (256 * 1024)
 #define VCE_V1_0_STACK_SIZE    (64 * 1024)
-#define VCE_V1_0_DATA_SIZE     (7808 * (AMDGPU_MAX_VCE_HANDLES + 1))
+#define VCE_V1_0_DATA_SIZE     (ALIGN(7808 * (AMDGPU_MAX_VCE_HANDLES + 1), VCE_V1_0_ALIGNMENT))
 #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK  0x02
 
 #define VCE_V1_0_GART_PAGE_START \
@@ -194,17 +195,22 @@ static int vce_v1_0_load_fw_signature(struct amdgpu_device *adev)
 {
        const struct common_firmware_header *hdr;
        struct vce_v1_0_fw_signature *sign;
-       unsigned int ucode_offset;
+       u32 ucode_offset;
+       u32 ucode_size;
        uint32_t chip_id;
        u32 *cpu_addr;
        int i;
 
        hdr = (const struct common_firmware_header *)adev->vce.fw->data;
        ucode_offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
+       ucode_size = hdr->ucode_size_bytes - sizeof(struct vce_v1_0_fw_signature *);
        cpu_addr = adev->vce.cpu_addr;
 
        sign = (void *)adev->vce.fw->data + ucode_offset;
 
+       if (ucode_size > VCE_V1_0_FW_SIZE - AMDGPU_VCE_FIRMWARE_OFFSET)
+               return -EINVAL;
+
        switch (adev->asic_type) {
        case CHIP_TAHITI:
                chip_id = 0x01000014;
@@ -236,7 +242,7 @@ static int vce_v1_0_load_fw_signature(struct amdgpu_device *adev)
        cpu_addr[4] = cpu_to_le32(le32_to_cpu(sign->length) + 64);
 
        memset_io(&cpu_addr[5], 0, 44);
-       memcpy_toio(&cpu_addr[16], &sign[1], hdr->ucode_size_bytes - sizeof(*sign));
+       memcpy_toio(&cpu_addr[16], &sign[1], ucode_size);
 
        cpu_addr += (le32_to_cpu(sign->length) + 64) / 4;
        memcpy_toio(&cpu_addr[0], &sign->val[i].sigval[0], 16);
@@ -317,17 +323,22 @@ static int vce_v1_0_mc_resume(struct amdgpu_device *adev)
        WREG32(mmVCE_VCPU_SCRATCH7, AMDGPU_MAX_VCE_HANDLES);
 
        offset =  adev->vce.gpu_addr + AMDGPU_VCE_FIRMWARE_OFFSET;
-       size = VCE_V1_0_FW_SIZE;
+       size = VCE_V1_0_FW_SIZE - AMDGPU_VCE_FIRMWARE_OFFSET;
        WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset);
        WREG32(mmVCE_VCPU_CACHE_SIZE0, size);
 
        offset += size;
        size = VCE_V1_0_STACK_SIZE;
+       WARN_ON(!IS_ALIGNED(offset, VCE_V1_0_ALIGNMENT));
+       WARN_ON(!IS_ALIGNED(size, VCE_V1_0_ALIGNMENT));
        WREG32(mmVCE_VCPU_CACHE_OFFSET1, offset);
        WREG32(mmVCE_VCPU_CACHE_SIZE1, size);
 
        offset += size;
        size = VCE_V1_0_DATA_SIZE;
+       WARN_ON(!IS_ALIGNED(offset, VCE_V1_0_ALIGNMENT));
+       WARN_ON(!IS_ALIGNED(size, VCE_V1_0_ALIGNMENT));
+       WARN_ON((offset + size - adev->vce.gpu_addr) > amdgpu_bo_size(adev->vce.vcpu_bo));
        WREG32(mmVCE_VCPU_CACHE_OFFSET2, offset);
        WREG32(mmVCE_VCPU_CACHE_SIZE2, size);