DF-3910 / trigger_analysis.c
/* * DF-3910 trigger/analysis — divide-by-zero panic in * tonga_thermal_setup_fan_table() (sys/dev/drm/amd/powerplay/smumgr/tonga_smumgr.c:2502-2513) * * Kernel path (hardware-gated: Tonga/Fiji + crafted VBIOS fan table): * process_pptables_v1_0.c copies usTMin/usTMed/usTHigh verbatim from the * ATOM_Tonga_Fan_Table / ATOM_Fiji_Fan_Table with no ordering or * distinctness validation (process_pptables_v1_0.c:941-986). If the VBIOS * supplies usTMed == usTMin (or usTHigh == usTMed), then * t_diff1 = usTMed - usTMin; (== 0) * slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); * divides by zero -> #DE -> kernel panic during DPM enable * (tonga_thermal_setup_fan_table is invoked from the enable task list). * Known DF-1274 covered only the SCLK/MCLK spread-spectrum rates * (tonga_smumgr.c:591/883); this fan-table site was not covered. * Per-file twins already filed: ci DF-1297, iceland DF-1323, fiji DF-1325, * polaris10 DF-1345. * * This harness performs the identical arithmetic in userspace: t_diff == 0 * raises SIGFPE exactly the way the kernel path raises #DE. */ #include <stdio.h> #include <stdint.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> static volatile sig_atomic_t got_fpe; static void fh(int sig) { (void)sig; got_fpe = 1; _exit(42); } int main(void) { uint32_t duty100 = 200; /* CG_FDO_CTRL1.FMAX_DUTY100, non-zero on hw */ uint32_t pwm_diff1 = 1234; /* usPWMMed - usPWMMin */ uint32_t usTMin = 4000, usTMed = 4000; /* crafted VBIOS: TMed == TMin */ uint32_t t_diff1 = usTMed - usTMin; /* == 0 */ signal(SIGFPE, fh); printf("duty100=%u pwm_diff1=%u usTMin=%u usTMed=%u -> t_diff1=%u\n", duty100, pwm_diff1, usTMin, usTMed, t_diff1); printf("evaluating (50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100 ...\n"); fflush(stdout); uint16_t slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); printf("no fault, slope1=%u (unexpected)\n", slope1); return 0; /* exit 42 via fh() == fault demonstrated */ } |