DF-5603 / df5603_harness.c
/* * DF-5603 - production-code KLD harness (no SD hardware required). * * Drives the stock, compiled-in mmc_switch() / mmc_switch_status() * helpers with a card-derived switch timeout of 0 - exactly the value * mmc.c computes at mmc.c:1663-1665 when a crafted (or mis-programmed) * eMMC reports CSD spec_vers >= 6 and EXT_CSD[EXT_CSD_GEN_CMD6_TIME]=0: * * ivar->cmd6_time = 10 * ivar->raw_ext_csd[EXT_CSD_GEN_CMD6_TIME]; * * which is 0, and then hands to the helpers at mmc.c:1672, :709, :828 * and :836 as the "timeout" argument: * * mmc_switch(..., ivar->cmd6_time, true); * mmc_switch_status(..., ivar->cmd6_time); * * mmc_subr.c:158 / :187 enforce the "timeout != 0" contract with * KASSERT(...), which on DragonFly's stock X86_64_GENERIC kernel * (sys/config/X86_64_GENERIC:56 "options INVARIANTS") is a live * panic - i.e. card enumeration turns into a guaranteed kernel panic. * * The two device_t arguments are two DISTINCT real devices (brdev != * reqdev) so that the helpers error-log branch - which dereferences * device_get_softc(brdev) as struct mmc_softc* - is never taken, and * the bridge dispatch (MMCBUS_WAIT_FOR_REQUEST on the parent of brdev) * falls back to kobj_error_method() == ENXIO (kern/subr_kobj.c:69-72), * making the post-KASSERT code path harmless when the KASSERT is * absent (patched kernel). This keeps the harness faithful to the * production call shape without a physical card. */ #include <sys/param.h> #include <sys/module.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/bus.h> #include <bus/mmc/mmc_subr.h> #include <bus/mmc/mmcreg.h> #define DF5603_RCA 1 /* any rca */ static device_t df5603_pick(const char *cn, int unit) { devclass_t dc; dc = devclass_find(cn); if (dc == NULL) return (NULL); return (devclass_get_device(dc, unit)); } static int df5603_modevent(module_t mod, int type, void *arg) { device_t brdev, reqdev; int err; switch (type) { case MOD_LOAD: /* Two distinct real devices, parent classes of which do * not implement mmcbus_if, so dispatch -> graceful ENXIO. */ brdev = df5603_pick("acpi", 0); reqdev = df5603_pick("acpi", 1); if (reqdev == NULL) reqdev = df5603_pick("pcib", 0); if (reqdev == NULL) reqdev = df5603_pick("isa", 0); if (brdev == NULL || reqdev == NULL || brdev == reqdev) { kprintf("DF-5603: no usable device pair, aborting\n"); return (ENXIO); } kprintf("DF-5603: calling mmc_switch(timeout=0) as mmc.c does " "for a card with EXT_CSD[248]=0 ...\n"); err = mmc_switch(brdev, reqdev, DF5603_RCA, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, EXT_CSD_HS_TIMING_HS, 0, true); kprintf("DF-5603: mmc_switch returned %d WITHOUT panicking " "(KASSERT not compiled in or fix applied)\n", err); kprintf("DF-5603: calling mmc_switch_status(timeout=0) " "(second KASSERT site) ...\n"); err = mmc_switch_status(brdev, reqdev, DF5603_RCA, 0); kprintf("DF-5603: mmc_switch_status returned %d WITHOUT " "panicking\n", err); break; default: break; } return (0); } static moduledata_t df5603_mod = { "df5603", df5603_modevent, NULL }; DECLARE_MODULE(df5603, df5603_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); |