DF-3621 / ci_ss_div0.c
/* DF-3621 / DF-3622 combined arithmetic proof: the two divide-by-zero sinks * fed by VBIOS-controlled zero spread-spectrum rate and zero MPLL reference * clock in amdgpu ci_dpm.c. * * Sink A (DF-3621) โ ci_calculate_sclk_params, ci_dpm.c:3337: * clk_s = reference_clock * 5 / (reference_divider * ss.rate); * Sink B (DF-3621) โ ci_calculate_mclk_params, ci_dpm.c:2981: * clks = reference_clock * 5 / ss.rate; * ss.rate comes from amdgpu_atombios_get_asic_ss_info (amdgpu_atombios.c:896): * v1: ss->rate = usSpreadRateInKhz (:936) โ NO zero check * v2: ss->rate = usSpreadRateIn10Hz / 100 (:954,:959) โ truncates to 0 for <100 * v3: ss->rate = usSpreadRateIn10Hz / 100 (:976,:984) โ truncates to 0 for <100 * * Sink C (DF-3622) โ ci_calculate_mclk_params, ci_dpm.c:2977: * tmp = (freq_nom / reference_clock); * reference_clock = adev->clock.mpll.reference_freq, assigned unchecked from * FirmwareInfo.usMemoryReferenceClock (amdgpu_atombios.c:659-660). * * Kernel integer division by zero on x86-64 => #DE => panic. * * Build: cc -O2 -Wall -o ci_ss_div0 ci_ss_div0.c && ./ci_ss_div0 * The divisions below are the real machine divisions with volatile sinks so * they cannot be optimized away; the SIGFPE trap is the userspace equivalent * of the kernel #DE panic. */ #include <stdio.h> #include <stdint.h> #include <signal.h> #include <stdlib.h> volatile uint32_t vsink; static void sigfpe_handler(int sig) { (void)sig; printf(" -> divide-by-zero trapped (%s in userspace == #DE in kernel) -> PANIC\n", sig == SIGFPE ? "SIGFPE" : "SIGILL"); exit(0); } int main(void) { /* volatile: models a value freshly read from the VBIOS image; the * compiler cannot const-fold the divisors away */ volatile uint16_t usSpreadRateIn10Hz = 50; /* VBIOS value < 100 */ volatile uint32_t usSpreadRateInKhz = 0; /* VBIOS v1 field == 0 */ volatile uint32_t usMemoryReferenceClock = 0;/* FirmwareInfo field == 0 */ uint32_t v2_rate = usSpreadRateIn10Hz; /* amdgpu_atombios.c:954 */ v2_rate /= 100; /* :959 -> 0 */ printf("V2/V3 parser: usSpreadRateIn10Hz=%u -> ss.rate after /=100 = %u\n\n", usSpreadRateIn10Hz, v2_rate); signal(SIGFPE, sigfpe_handler); signal(SIGILL, sigfpe_handler); printf("[A] ci_calculate_sclk_params ci_dpm.c:3337 with ss.rate=0 (v1 zero or v2/v3 truncation)\n"); printf(" clk_s = reference_clock * 5 / (reference_divider * ss.rate)\n"); fflush(stdout); vsink = 100000 * 5 / (2 * v2_rate); /* ci_dpm.c:3337 โ rate==0 */ printf("[B] ci_calculate_mclk_params ci_dpm.c:2981 with ss.rate=0\n"); printf(" clks = reference_clock * 5 / ss.rate\n"); fflush(stdout); vsink = 100000 * 5 / usSpreadRateInKhz; /* ci_dpm.c:2981 โ v1 usSpreadRateInKhz==0 */ printf("[C] ci_calculate_mclk_params ci_dpm.c:2977 with mpll.reference_freq=0\n"); printf(" (usMemoryReferenceClock=0 from FirmwareInfo, amdgpu_atombios.c:659-660)\n"); printf(" tmp = freq_nom / reference_clock\n"); fflush(stdout); vsink = 600000 / usMemoryReferenceClock;/* ci_dpm.c:2977 โ reference_clock==0 */ printf("no trap (unexpected)\n"); return 0; } |