--- a/sys/dev/drm/amd/powerplay/hwmgr/vega10_processpptables.c +++ b/sys/dev/drm/amd/powerplay/hwmgr/vega10_processpptables.c @@ -34,6 +34,63 @@ #define NUM_DSPCLK_LEVELS 8 #define VEGA10_ENGINECLOCK_HARDMAX 198000 +/* + * Central bounds-validation layer for the Vega10 (ATOM_Vega10_*) PowerPlay + * table family — the V1 treatment (process_pptables_v1_0.c, DF-4388) + * applied to this parser. + * + * Every firmware-supplied USHORT offset, UCHAR count and UCHAR index is + * proven against the actual size of the PowerPlay table image + * (hwmgr->soft_pp_table / hwmgr->soft_pp_table_size, cached by + * get_powerplay_table()) before it is dereferenced, and entry counts are + * clamped both to what the image can hold and to the capacities of the + * destination allocations made in this file (VDDC lookup max_levels=8, + * VDDMEM/VDDCI lookup max_levels=4, DCEFCLK pioneer path NUM_DSPCLK_LEVELS). + */ + +static bool vega10_pp_table_range_ok(const struct pp_hwmgr *hwmgr, + uint32_t off, uint32_t len) +{ + if (hwmgr->soft_pp_table == NULL || hwmgr->soft_pp_table_size == 0) + return false; + if (off >= hwmgr->soft_pp_table_size) + return false; + return len <= ((uint32_t)hwmgr->soft_pp_table_size - off); +} + +static uint32_t vega10_pp_table_offset_of(const struct pp_hwmgr *hwmgr, + const void *p) +{ + return (uint32_t)((const uint8_t *)p - + (const uint8_t *)hwmgr->soft_pp_table); +} + +/* + * Clamp a firmware entry count to the number of entries that actually fit + * in the table image. off is the offset of the sub-table, header_size + * covers ucRevId + ucNumEntries, entry_size is one entry. + */ +static uint8_t vega10_pp_clamp_count(const struct pp_hwmgr *hwmgr, + uint32_t off, uint32_t header_size, + uint8_t num, uint32_t entry_size) +{ + uint64_t avail; + + if (!vega10_pp_table_range_ok(hwmgr, off, header_size + entry_size)) + return 0; + avail = ((uint64_t)hwmgr->soft_pp_table_size - off - header_size) / + entry_size; + if (num > avail) + num = (avail > 255) ? 255 : (uint8_t)avail; + return num; +} + +/* Validate that a sub-table pointer derived as powerplay_table + USHORT + * offset actually holds hdr_len bytes of the image. */ +#define VEGA10_SUBTABLE_OK(hwmgr, ptr, hdr_len) \ + vega10_pp_table_range_ok((hwmgr), \ + vega10_pp_table_offset_of((hwmgr), (ptr)), (hdr_len)) + static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable, enum phm_platform_caps cap) { @@ -79,6 +136,10 @@ "State table is not set!", return -1); PP_ASSERT_WITH_CODE(powerplay_table->sHeader.structuresize > 0, "Invalid PowerPlay Table!", return -1); + PP_ASSERT_WITH_CODE(vega10_pp_table_range_ok(hwmgr, + le16_to_cpu(powerplay_table->usStateArrayOffset), + offsetof(ATOM_Vega10_State_Array, states)), + "State array out of range!", return -1); PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0, "Invalid PowerPlay Table!", return -1); @@ -131,6 +192,10 @@ PP_ASSERT_WITH_CODE((powerplay_table->usThermalControllerOffset != 0), "Thermal controller table not set!", return -EINVAL); + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, thermal_controller, + sizeof(ATOM_Vega10_Thermal_Controller)), + "Thermal controller table out of range!", return -EINVAL); + hwmgr->thermal_controller.ucType = thermal_controller->ucType; hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine; hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress; @@ -163,9 +228,15 @@ (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usFanTableOffset)); + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, header, 1), + "Fan table out of range!", return -EINVAL); + if (header->ucRevId == 10) { fan_table_v1 = (ATOM_Vega10_Fan_Table *)header; + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, header, + sizeof(ATOM_Vega10_Fan_Table)), + "Fan table out of range!", return -EINVAL); PP_ASSERT_WITH_CODE((fan_table_v1->ucRevId >= 8), "Invalid Input Fan Table!", return -EINVAL); @@ -210,6 +281,10 @@ } else if (header->ucRevId > 10) { fan_table_v2 = (ATOM_Vega10_Fan_Table_V2 *)header; + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, header, + sizeof(ATOM_Vega10_Fan_Table_V2)), + "Fan table out of range!", return -EINVAL); + hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution = fan_table_v2->ucFanParameters & ATOM_VEGA10_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; hwmgr->thermal_controller.fanInfo.ulMinRPM = fan_table_v2->ucFanMinRPM * 100UL; @@ -265,12 +340,23 @@ le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset)); bool is_acg_enabled = false; ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_v2; + uint8_t gfxclk_num_entries; - if (gfxclk_dep_table->ucRevId == 1) { + if (powerplay_table->usGfxclkDependencyTableOffset && + VEGA10_SUBTABLE_OK(hwmgr, gfxclk_dep_table, + offsetof(ATOM_Vega10_GFXCLK_Dependency_Table, entries)) && + gfxclk_dep_table->ucRevId == 1) { + gfxclk_num_entries = vega10_pp_clamp_count(hwmgr, + vega10_pp_table_offset_of(hwmgr, gfxclk_dep_table), + offsetof(ATOM_Vega10_GFXCLK_Dependency_Table, entries), + gfxclk_dep_table->ucNumEntries, + sizeof(ATOM_Vega10_GFXCLK_Dependency_Record_V2)); + PP_ASSERT_WITH_CODE((gfxclk_num_entries != 0), + "Invalid GFXCLK dependency table!", return -EINVAL); patom_record_v2 = (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)gfxclk_dep_table->entries; is_acg_enabled = - (bool)patom_record_v2[gfxclk_dep_table->ucNumEntries-1].ucACGEnable; + (bool)patom_record_v2[gfxclk_num_entries-1].ucACGEnable; } if (powerplay_table->ulMaxODEngineClock > VEGA10_ENGINECLOCK_HARDMAX && @@ -296,23 +382,29 @@ const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table) { uint32_t table_size, i; + uint8_t num_entries; const ATOM_Vega10_MM_Dependency_Record *mm_dependency_record; phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table; - PP_ASSERT_WITH_CODE((mm_dependency_table->ucNumEntries != 0), + num_entries = vega10_pp_clamp_count(hwmgr, + vega10_pp_table_offset_of(hwmgr, mm_dependency_table), + offsetof(ATOM_Vega10_MM_Dependency_Table, entries), + mm_dependency_table->ucNumEntries, + sizeof(ATOM_Vega10_MM_Dependency_Record)); + PP_ASSERT_WITH_CODE((num_entries != 0), "Invalid PowerPlay Table!", return -1); table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record) * - mm_dependency_table->ucNumEntries; + num_entries; mm_table = kzalloc(table_size, GFP_KERNEL); if (!mm_table) return -ENOMEM; - mm_table->count = mm_dependency_table->ucNumEntries; + mm_table->count = num_entries; - for (i = 0; i < mm_dependency_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { mm_dependency_record = &mm_dependency_table->entries[i]; mm_table->entries[i].vddcInd = mm_dependency_record->ucVddcInd; mm_table->entries[i].samclock = @@ -389,7 +481,13 @@ if (!tdp_table) return -ENOMEM; + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, table, 1), + "PowerTune table out of range!", return -EINVAL); + if (table->ucRevId == 5) { + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, table, + sizeof(ATOM_Vega10_PowerTune_Table)), + "PowerTune table out of range!", return -EINVAL); power_tune_table = (ATOM_Vega10_PowerTune_Table *)table; tdp_table->usMaximumPowerDeliveryLimit = le16_to_cpu(power_tune_table->usSocketPowerLimit); tdp_table->usTDC = le16_to_cpu(power_tune_table->usTdcLimit); @@ -424,6 +522,9 @@ tdp_table->ucPlx_I2C_LineSDA = power_tune_table->ucPlx_I2C_LineSDA; hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(power_tune_table->usLoadLineResistance); } else if (table->ucRevId == 6) { + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, table, + sizeof(ATOM_Vega10_PowerTune_Table_V2)), + "PowerTune table out of range!", return -EINVAL); power_tune_table_v2 = (ATOM_Vega10_PowerTune_Table_V2 *)table; tdp_table->usMaximumPowerDeliveryLimit = le16_to_cpu(power_tune_table_v2->usSocketPowerLimit); tdp_table->usTDC = le16_to_cpu(power_tune_table_v2->usTdcLimit); @@ -470,6 +571,9 @@ hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(power_tune_table_v2->usLoadLineResistance); } else { + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, table, + sizeof(ATOM_Vega10_PowerTune_Table_V3)), + "PowerTune table out of range!", return -EINVAL); power_tune_table_v3 = (ATOM_Vega10_PowerTune_Table_V3 *)table; tdp_table->usMaximumPowerDeliveryLimit = le16_to_cpu(power_tune_table_v3->usSocketPowerLimit); tdp_table->usTDC = le16_to_cpu(power_tune_table_v3->usTdcLimit); @@ -523,23 +627,29 @@ const ATOM_Vega10_SOCCLK_Dependency_Table *clk_dep_table) { uint32_t table_size, i; + uint8_t num_entries; phm_ppt_v1_clock_voltage_dependency_table *clk_table; - PP_ASSERT_WITH_CODE(clk_dep_table->ucNumEntries, + num_entries = vega10_pp_clamp_count(hwmgr, + vega10_pp_table_offset_of(hwmgr, clk_dep_table), + offsetof(ATOM_Vega10_SOCCLK_Dependency_Table, entries), + clk_dep_table->ucNumEntries, + sizeof(ATOM_Vega10_CLK_Dependency_Record)); + PP_ASSERT_WITH_CODE(num_entries, "Invalid PowerPlay Table!", return -1); table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) * - clk_dep_table->ucNumEntries; + num_entries; clk_table = kzalloc(table_size, GFP_KERNEL); if (!clk_table) return -ENOMEM; - clk_table->count = (uint32_t)clk_dep_table->ucNumEntries; + clk_table->count = (uint32_t)num_entries; - for (i = 0; i < clk_dep_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { clk_table->entries[i].vddInd = clk_dep_table->entries[i].ucVddInd; clk_table->entries[i].clk = @@ -557,23 +667,29 @@ const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table) { uint32_t table_size, i; + uint8_t num_entries; phm_ppt_v1_clock_voltage_dependency_table *mclk_table; - PP_ASSERT_WITH_CODE(mclk_dep_table->ucNumEntries, + num_entries = vega10_pp_clamp_count(hwmgr, + vega10_pp_table_offset_of(hwmgr, mclk_dep_table), + offsetof(ATOM_Vega10_MCLK_Dependency_Table, entries), + mclk_dep_table->ucNumEntries, + sizeof(ATOM_Vega10_MCLK_Dependency_Record)); + PP_ASSERT_WITH_CODE(num_entries, "Invalid PowerPlay Table!", return -1); table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) * - mclk_dep_table->ucNumEntries; + num_entries; mclk_table = kzalloc(table_size, GFP_KERNEL); if (!mclk_table) return -ENOMEM; - mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries; + mclk_table->count = (uint32_t)num_entries; - for (i = 0; i < mclk_dep_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { mclk_table->entries[i].vddInd = mclk_dep_table->entries[i].ucVddInd; mclk_table->entries[i].vddciInd = @@ -599,20 +715,33 @@ struct phm_ppt_v1_clock_voltage_dependency_table *clk_table; ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_v2; + uint8_t num_entries; - PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), + num_entries = vega10_pp_clamp_count(hwmgr, + vega10_pp_table_offset_of(hwmgr, clk_dep_table), + offsetof(ATOM_Vega10_GFXCLK_Dependency_Table, entries), + clk_dep_table->ucNumEntries, + (clk_dep_table->ucRevId == 1) ? + sizeof(ATOM_Vega10_GFXCLK_Dependency_Record_V2) : + sizeof(ATOM_Vega10_GFXCLK_Dependency_Record)); + PP_ASSERT_WITH_CODE((num_entries != 0), "Invalid PowerPlay Table!", return -1); + PP_ASSERT_WITH_CODE((clk_dep_table->ucRevId == 0 || + clk_dep_table->ucRevId == 1), + "Unsupported GFXClockDependencyTable Revision!", + return -EINVAL); + table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) * - clk_dep_table->ucNumEntries; + num_entries; clk_table = kzalloc(table_size, GFP_KERNEL); if (!clk_table) return -ENOMEM; - clk_table->count = clk_dep_table->ucNumEntries; + clk_table->count = num_entries; if (clk_dep_table->ucRevId == 0) { for (i = 0; i < clk_table->count; i++) { @@ -628,7 +757,7 @@ clk_table->entries[i].sclk_offset = le16_to_cpu(clk_dep_table->entries[i].usAVFSOffset); } - } else if (clk_dep_table->ucRevId == 1) { + } else { patom_record_v2 = (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)clk_dep_table->entries; for (i = 0; i < clk_table->count; i++) { clk_table->entries[i].vddInd = @@ -644,11 +773,6 @@ le16_to_cpu(patom_record_v2->usAVFSOffset); patom_record_v2++; } - } else { - kfree(clk_table); - PP_ASSERT_WITH_CODE(false, - "Unsupported GFXClockDependencyTable Revision!", - return -EINVAL); } *pp_vega10_clk_dep_table = clk_table; @@ -665,20 +789,26 @@ uint32_t table_size, i; struct phm_ppt_v1_clock_voltage_dependency_table *clk_table; + uint8_t num_entries; - PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), + num_entries = vega10_pp_clamp_count(hwmgr, + vega10_pp_table_offset_of(hwmgr, clk_dep_table), + offsetof(ATOM_Vega10_PIXCLK_Dependency_Table, entries), + clk_dep_table->ucNumEntries, + sizeof(ATOM_Vega10_CLK_Dependency_Record)); + PP_ASSERT_WITH_CODE((num_entries != 0), "Invalid PowerPlay Table!", return -1); table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) * - clk_dep_table->ucNumEntries; + num_entries; clk_table = kzalloc(table_size, GFP_KERNEL); if (!clk_table) return -ENOMEM; - clk_table->count = clk_dep_table->ucNumEntries; + clk_table->count = num_entries; for (i = 0; i < clk_table->count; i++) { clk_table->entries[i].vddInd = @@ -700,13 +830,24 @@ { uint32_t table_size, i; uint8_t num_entries; + uint8_t copy_entries; struct phm_ppt_v1_clock_voltage_dependency_table *clk_table; uint32_t dev_id; uint32_t rev_id; struct amdgpu_device *adev = hwmgr->adev; - PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), + /* + * Clamp the firmware count to what the image can hold; the pioneer + * workaround below may still cap the destination below it, so the + * copy loop must run on num_entries, never on ucNumEntries. + */ + copy_entries = vega10_pp_clamp_count(hwmgr, + vega10_pp_table_offset_of(hwmgr, clk_dep_table), + offsetof(ATOM_Vega10_DCEFCLK_Dependency_Table, entries), + clk_dep_table->ucNumEntries, + sizeof(ATOM_Vega10_CLK_Dependency_Record)); + PP_ASSERT_WITH_CODE((copy_entries != 0), "Invalid PowerPlay Table!", return -1); /* @@ -719,11 +860,11 @@ rev_id = adev->pdev->revision; if (dev_id == 0x6863 && rev_id == 0 && - clk_dep_table->entries[clk_dep_table->ucNumEntries - 1].ulClk < 90000) - num_entries = clk_dep_table->ucNumEntries + 1 > NUM_DSPCLK_LEVELS ? - NUM_DSPCLK_LEVELS : clk_dep_table->ucNumEntries + 1; + clk_dep_table->entries[copy_entries - 1].ulClk < 90000) + num_entries = copy_entries + 1 > NUM_DSPCLK_LEVELS ? + NUM_DSPCLK_LEVELS : copy_entries + 1; else - num_entries = clk_dep_table->ucNumEntries; + num_entries = copy_entries; table_size = sizeof(uint32_t) + @@ -737,7 +878,7 @@ clk_table->count = (uint32_t)num_entries; - for (i = 0; i < clk_dep_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { clk_table->entries[i].vddInd = clk_dep_table->entries[i].ucVddInd; clk_table->entries[i].clk = @@ -765,10 +906,28 @@ const ATOM_Vega10_PCIE_Table *atom_pcie_table = (ATOM_Vega10_PCIE_Table *)table; + /* + * The PCIE table is matched against the GFXCLK DPM levels; without a + * parsed GFXCLK dependency table there is nothing sane to match. + */ + PP_ASSERT_WITH_CODE((table_info->vdd_dep_on_sclk != NULL), + "GFXCLK dependency table missing!", return -EINVAL); + + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, atom_pcie_table, + offsetof(ATOM_Vega10_PCIE_Table, entries)), + "PCIE table out of range!", return -EINVAL); + PP_ASSERT_WITH_CODE(atom_pcie_table->ucNumEntries, "Invalid PowerPlay Table!", return 0); + PP_ASSERT_WITH_CODE(vega10_pp_clamp_count(hwmgr, + vega10_pp_table_offset_of(hwmgr, atom_pcie_table), + offsetof(ATOM_Vega10_PCIE_Table, entries), + atom_pcie_table->ucNumEntries, + sizeof(ATOM_Vega10_PCIE_Record)) != 0, + "PCIE table entries exceed image!", return -EINVAL); + table_size = sizeof(uint32_t) + sizeof(struct phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries; @@ -807,6 +966,11 @@ struct phm_clock_and_voltage_limits *limits, const ATOM_Vega10_Hard_Limit_Table *limit_table) { + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, limit_table, + offsetof(ATOM_Vega10_Hard_Limit_Table, entries) + + sizeof(ATOM_Vega10_Hard_Limit_Record)), + "Hard limit table out of range!", return -1); + PP_ASSERT_WITH_CODE(limit_table->ucNumEntries, "Invalid PowerPlay Table!", return -1); @@ -1018,11 +1182,21 @@ uint32_t max_levels) { uint32_t table_size, i; + uint8_t num_entries; phm_ppt_v1_voltage_lookup_table *table; - PP_ASSERT_WITH_CODE((vddc_lookup_pp_tables->ucNumEntries != 0), + num_entries = vega10_pp_clamp_count(hwmgr, + vega10_pp_table_offset_of(hwmgr, vddc_lookup_pp_tables), + offsetof(ATOM_Vega10_Voltage_Lookup_Table, entries), + vddc_lookup_pp_tables->ucNumEntries, + sizeof(ATOM_Vega10_Voltage_Lookup_Record)); + PP_ASSERT_WITH_CODE((num_entries != 0), "Invalid SOC_VDDD Lookup Table!", return 1); + /* destination capacity: the caller kzallocs max_levels records */ + if (num_entries > max_levels) + num_entries = max_levels; + table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels; @@ -1031,9 +1205,9 @@ if (table == NULL) return -ENOMEM; - table->count = vddc_lookup_pp_tables->ucNumEntries; + table->count = num_entries; - for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) + for (i = 0; i < num_entries; i++) table->entries[i].us_vdd = le16_to_cpu(vddc_lookup_pp_tables->entries[i].usVdd); @@ -1047,6 +1221,7 @@ const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) { int result = 0; + int ret; struct phm_ppt_v2_information *pp_table_info = (struct phm_ppt_v2_information *)(hwmgr->pptable); uint32_t disable_power_control = 0; @@ -1105,8 +1280,10 @@ (ATOM_Vega10_Voltage_Lookup_Table *) (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usVddcLookupTableOffset)); - result = get_vddc_lookup_table(hwmgr, + ret = get_vddc_lookup_table(hwmgr, &pp_table_info->vddc_lookup_table, vddc_table, 8); + if (ret) + result = ret; } if (powerplay_table->usVddmemLookupTableOffset) { @@ -1114,8 +1291,10 @@ (ATOM_Vega10_Voltage_Lookup_Table *) (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usVddmemLookupTableOffset)); - result = get_vddc_lookup_table(hwmgr, + ret = get_vddc_lookup_table(hwmgr, &pp_table_info->vddmem_lookup_table, vdd_mem_table, 4); + if (ret) + result = ret; } if (powerplay_table->usVddciLookupTableOffset) { @@ -1123,8 +1302,10 @@ (ATOM_Vega10_Voltage_Lookup_Table *) (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usVddciLookupTableOffset)); - result = get_vddc_lookup_table(hwmgr, + ret = get_vddc_lookup_table(hwmgr, &pp_table_info->vddci_lookup_table, vddci_table, 4); + if (ret) + result = ret; } return result; @@ -1242,6 +1423,12 @@ PP_ASSERT_WITH_CODE((pp_table->sHeader.format_revision >= ATOM_Vega10_TABLE_REVISION_VEGA10), "Incorrect PowerPlay table revision!", return -1); + PP_ASSERT_WITH_CODE((pp_table->usStateArrayOffset > 0), + "Invalid PowerPlay Table State Array Offset.", return -1); + PP_ASSERT_WITH_CODE(vega10_pp_table_range_ok(hwmgr, + le16_to_cpu(pp_table->usStateArrayOffset), + offsetof(ATOM_Vega10_State_Array, states)), + "Invalid PowerPlay Table State Array Offset.", return -1); state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)pp_table) + le16_to_cpu(pp_table->usStateArrayOffset)); @@ -1305,7 +1492,13 @@ PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0, "Invalid PowerPlay Table State Array.", return -1); - PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries), + PP_ASSERT_WITH_CODE((entry_index < state_arrays->ucNumEntries), + "Invalid PowerPlay Table State Array Entry.", + return -1); + PP_ASSERT_WITH_CODE(VEGA10_SUBTABLE_OK(hwmgr, state_arrays, + offsetof(ATOM_Vega10_State_Array, states) + + ((uint32_t)entry_index + 1) * + sizeof(ATOM_Vega10_State)), "Invalid PowerPlay Table State Array Entry.", return -1);