DF-4665 / smu7_odn_overflow_patched.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | /* * DF-4665 PATCHED twin — same harness as smu7_odn_overflow.c but the copy * helper carries the fix.diff guard (max_entries parameter + clamp, and the * smu7 call sites pass MAX_REGULAR_DPM_NUMBER). Expected: entries[8..] * untouched, canaries intact, dep_table->count == 8. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> struct phm_ppt_v1_clock_voltage_dependency_record { uint32_t clk; uint8_t vddInd; uint8_t vddciInd; uint8_t mvddInd; uint16_t vdd_offset; uint16_t vddc; uint16_t vddgfx; uint16_t vddci; uint16_t mvdd; uint8_t phases; uint8_t cks_enable; uint8_t cks_voffset; uint32_t sclk_offset; }; struct phm_ppt_v1_clock_voltage_dependency_table { uint32_t count; struct phm_ppt_v1_clock_voltage_dependency_record entries[1]; }; #define MAX_REGULAR_DPM_NUMBER 8 struct phm_odn_performance_level { uint32_t clock; uint32_t vddc; int enabled; }; struct phm_odn_clock_levels { uint32_t size; uint32_t options; uint32_t flags; uint32_t num_of_pl; struct phm_odn_performance_level entries[8]; }; struct smu7_odn_clock_voltage_dependency_table { uint32_t count; struct phm_ppt_v1_clock_voltage_dependency_record entries[MAX_REGULAR_DPM_NUMBER]; }; struct smu7_odn_dpm_table { struct phm_odn_clock_levels odn_core_clock_dpm_levels; struct phm_odn_clock_levels odn_memory_clock_dpm_levels; struct smu7_odn_clock_voltage_dependency_table vdd_dependency_on_sclk; struct smu7_odn_clock_voltage_dependency_table vdd_dependency_on_mclk; uint32_t odn_mclk_min_limit; uint32_t min_vddc; uint32_t max_vddc; }; struct smu7_backend_like { char dummy_dpm_tables[1024]; struct smu7_odn_dpm_table odn_dpm_table; uint32_t canary[64]; }; #define CANARY 0xDEADBEEFU #define EINVAL 22 /* PATCHED per fix.diff: destination capacity is passed and clamped */ int smu_get_voltage_dependency_table_ppt_v1_fixed( const struct phm_ppt_v1_clock_voltage_dependency_table *allowed_dep_table, struct phm_ppt_v1_clock_voltage_dependency_table *dep_table, uint32_t max_entries) { uint32_t i; if (!allowed_dep_table || allowed_dep_table->count == 0) return -EINVAL; dep_table->count = (allowed_dep_table->count > max_entries) ? max_entries : allowed_dep_table->count; for (i = 0; i < dep_table->count; i++) { dep_table->entries[i].clk = allowed_dep_table->entries[i].clk; dep_table->entries[i].vddInd = allowed_dep_table->entries[i].vddInd; dep_table->entries[i].vdd_offset = allowed_dep_table->entries[i].vdd_offset; dep_table->entries[i].vddc = allowed_dep_table->entries[i].vddc; dep_table->entries[i].vddgfx = allowed_dep_table->entries[i].vddgfx; dep_table->entries[i].vddci = allowed_dep_table->entries[i].vddci; dep_table->entries[i].mvdd = allowed_dep_table->entries[i].mvdd; dep_table->entries[i].phases = allowed_dep_table->entries[i].phases; dep_table->entries[i].cks_enable = allowed_dep_table->entries[i].cks_enable; dep_table->entries[i].cks_voffset = allowed_dep_table->entries[i].cks_voffset; } return 0; } static struct phm_ppt_v1_clock_voltage_dependency_table *make_dep_table(unsigned count, unsigned distinct_clocks) { struct phm_ppt_v1_clock_voltage_dependency_table *t; unsigned i; t = calloc(1, sizeof(*t) + sizeof(struct phm_ppt_v1_clock_voltage_dependency_record) * (count + 1)); if (!t) { perror("calloc"); exit(1); } t->count = count; for (i = 0; i < count; i++) { t->entries[i].clk = 100000 + (i % distinct_clocks) * 2500; t->entries[i].vddInd = (uint8_t)i; t->entries[i].vdd_offset = (uint16_t)(0x1100 + i); t->entries[i].vddc = (uint16_t)(900 + i); t->entries[i].vddgfx = (uint16_t)(950 + i); t->entries[i].vddci = (uint16_t)(1000 + i); t->entries[i].mvdd = (uint16_t)(1050 + i); t->entries[i].phases = 1; t->entries[i].cks_enable = (uint8_t)(i & 1); t->entries[i].sclk_offset = 0x41410000u + i; } return t; } static unsigned count_smashed(const uint32_t *c, unsigned n) { unsigned i, s = 0; for (i = 0; i < n; i++) if (c[i] != CANARY) s++; return s; } int main(int argc, char **argv) { unsigned count = (argc > 1) ? (unsigned)atoi(argv[1]) : 16; unsigned distinct = (argc > 2) ? (unsigned)atoi(argv[2]) : 2; struct smu7_backend_like *be = calloc(1, sizeof(*be)); struct phm_ppt_v1_clock_voltage_dependency_table *dep = make_dep_table(count, distinct); for (size_t k = 0; k < 64; k++) be->canary[k] = CANARY; smu_get_voltage_dependency_table_ppt_v1_fixed(dep, (struct phm_ppt_v1_clock_voltage_dependency_table *) &be->odn_dpm_table.vdd_dependency_on_sclk, MAX_REGULAR_DPM_NUMBER); /* the fix: smu7 call sites pass 8 */ printf("[patched] dep->count=%u -> stored count = %u (clamped to MAX_REGULAR_DPM_NUMBER)\n", count, be->odn_dpm_table.vdd_dependency_on_sclk.count); printf("[patched] vdd_dependency_on_mclk.count still = %u\n", be->odn_dpm_table.vdd_dependency_on_mclk.count); printf("[patched] canary words smashed: %u/64\n", count_smashed(be->canary, 64)); if (be->odn_dpm_table.vdd_dependency_on_sclk.count <= MAX_REGULAR_DPM_NUMBER && count_smashed(be->canary, 64) == 0 && be->odn_dpm_table.vdd_dependency_on_mclk.count == 0) printf("FIX VALIDATED: no out-of-bounds writes with clamped copy\n"); else { printf("FIX FAILED\n"); return 1; } return 0; } |