DF-4388 / v1_clamp_test.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 | /* * DF-4388 unit test: host-side replica of the central V1 validation layer * added to sys/dev/drm/amd/powerplay/hwmgr/process_pptables_v1_0.c * (pp_v1_table_range_ok / pp_v1_clamp_count / the VCE + state-entry index * treatment). This exercises the exact clamp/reject arithmetic that the * patched kernel parser applies to firmware-supplied values. * * Build: cc -O2 -o v1_clamp_test v1_clamp_test.c * Run: ./v1_clamp_test ; echoes PASS/FAIL per case, exit != 0 on FAIL */ #include <stdio.h> #include <stdint.h> #include <stdbool.h> #include <string.h> /* ---- replica of the patched helpers (byte-identical logic) ---- */ static uint8_t image[2048]; static uint32_t image_size; static bool pp_v1_table_range_ok(uint32_t off, uint32_t len) { if (off >= image_size) return false; return len <= (image_size - off); } static uint8_t pp_v1_clamp_count(uint32_t off, uint32_t header_size, uint8_t num, uint32_t entry_size) { uint64_t avail; if (!pp_v1_table_range_ok(off, header_size + entry_size)) return 0; avail = ((uint64_t)image_size - off - header_size) / entry_size; if (num > avail) num = (avail > 255) ? 255 : (uint8_t)avail; return num; } static int failures; #define CHECK(name, cond) do { \ printf("%-58s %s\n", name, (cond) ? "PASS" : "FAIL"); \ if (!(cond)) failures++; \ } while (0) int main(void) { uint8_t r; /* realistic small PowerPlay image */ image_size = 512; /* 1. DF-1574: lookup count 255 vs dest 16 and image (8 fit) */ r = pp_v1_clamp_count(16, 2, 255, 8); /* (512-16-2)/8 = 61 */ CHECK("DF-1574 count255 clamp->min(61)", r == 61); CHECK("DF-1574 dest clamp min(61,16)==16", (uint8_t)(r > 16 ? 16 : r) == 16); /* 2. truncated image: only 1 entry fits */ image_size = 16 + 2 + 8; /* header+1 entry */ r = pp_v1_clamp_count(16, 2, 200, 8); CHECK("truncated table: count clamps to 1", r == 1); /* 3. header itself outside image -> 0 (reject) */ r = pp_v1_clamp_count(2000, 2, 5, 8); CHECK("offset past image -> 0", r == 0); /* 4. USHORT offset 0xffff -> range check false */ CHECK("offset 0xffff rejected", !pp_v1_table_range_ok(0xffff, 4)); /* 5. DF-1577: entry_index == ucNumEntries must be rejected */ { uint8_t ucNumEntries = 4, entry_index = 4; CHECK("DF-1577 entry_index==ucNumEntries rejected", !(entry_index < ucNumEntries)); entry_index = 3; CHECK("DF-1577 entry_index<ucNumEntries accepted", entry_index < ucNumEntries); } /* 6. VCE indices: UCHAR 255 vs 6 available entries -> fallback 0 */ { uint8_t ucSCLKIndex = 255, sclk_idx; image_size = 512; r = pp_v1_clamp_count(64, 2, 0xFF, 12); /* (512-64-2)/12=37 */ sclk_idx = (ucSCLKIndex >= r) ? 0 : ucSCLKIndex; CHECK("VCE ucSCLKIndex 255 clamped to 0", sclk_idx == 0); } /* 7. new finding: num_vce_state_tables 255 vs AMD_MAX_VCE_LEVELS 6 */ { int i = 255, AMD_MAX_VCE_LEVELS = 6; if (i > AMD_MAX_VCE_LEVELS) i = AMD_MAX_VCE_LEVELS; CHECK("VCE state count 255 clamped to 6", i == 6); } /* 8. dep-count destination clamps (GraphicsLevel[8]/MemoryLevel[4]) */ { uint8_t sclk = pp_v1_clamp_count(16, 2, 255, 12); /* 41 */ uint8_t mclk = pp_v1_clamp_count(16, 2, 255, 14); /* 35 */ if (sclk > 8) sclk = 8; if (mclk > 4) mclk = 4; CHECK("sclk dep count clamped to 8 (GraphicsLevel[8])", sclk == 8); CHECK("mclk dep count clamped to 4 (MemoryLevel[4])", mclk == 4); } printf(failures ? "\n%d FAILURE(S)\n" : "\nALL CASES PASS\n", failures); return failures ? 1 : 0; } |