DF-4981 / jmsink.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 | /* * DF-4981 sink demonstration module (jmphy). * * Executes the exact terminal sequence of the jmphy no-media attach chain: * * jmphy_attach (jmphy.c:119-129): BMSR reports zero media bits and * (no BMSR_EXTSTAT, or EXTSR media bits zero) -> the "no media present" * branch at jmphy.c:124-127 prints and SKIPS mii_phy_add_media(), * then jmphy.c:131 still calls MIIBUS_MEDIAINIT(sc->mii_dev) * -> miibus_mediainit (mii.c:228-246): the parent (jme(4), which * implements no miibus_mediainit method -- if_jme.c:218-220 -- and * attaches the bus via mii_phy_probe at if_jme.c:1028) adds no media * of its own, so the ifm_list walk finds NOTHING, media stays 0, * and mii.c:244 calls ifmedia_set(&mii->mii_media, 0) * -> ifmedia_set (sys/net/if_media.c:168-175): ifmedia_match() on an * empty list returns NULL -> kprintf + panic("ifmedia_set") * * Only the PHY hardware state (a JMicron JMP211/JMP202 whose ID registers * match miidevs JMICRON/JMP211|JMP202 while BMSR reads 0 -- e.g. jme's SMI * read timing out returns 0, if_jme.c:303-308 -- i.e. a stuck/powered-down * PHY) is not emulatable on this guest; the kernel-side sink is executed * verbatim. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/bus.h> #include <sys/conf.h> #include <sys/sysctl.h> #include <sys/systm.h> #include <net/if.h> #include <net/if_media.h> static struct ifmedia ifm; static int jmsink_fire(SYSCTL_HANDLER_ARGS) { int v = 0, error; struct ifmedia_entry *m; int media = 0; error = sysctl_handle_opaque(oidp, &v, sizeof(v), req); if (error != 0 || req->newptr == NULL) return (error); kprintf("jmsink: ifmedia_init (empty list)\n"); ifmedia_init(&ifm, 0, NULL, NULL); /* mii.c:236-240 verbatim (miibus_mediainit list walk) */ for (m = LIST_FIRST(&ifm.ifm_list); m != NULL; m = LIST_NEXT(m, ifm_list)) { media = m->ifm_media; if (media == (IFM_ETHER | IFM_AUTO)) break; } kprintf("jmsink: list walk done, media=0x%x; calling ifmedia_set (mii.c:244)\n", media); ifmedia_set(&ifm, media); /* expected: panic("ifmedia_set") */ kprintf("jmsink: NOT REACHED\n"); return (0); } /* * DF-4981 fix-mechanism check: * * The proposed fix (fix.diff) makes jmphy_attach call * mii_phy_add_media() unconditionally. With zero capabilities that adds * exactly the IFM_NONE fallback entry (mii_physubr.c:235-237: * "if ((sc->mii_flags & MIIF_NOISOLATE) == 0) ADD(IFM_ETHER|IFM_NONE ...)"; * jmphy never sets MIIF_NOISOLATE and jme passes no such flag through * mii_phy_probe), so miibus_mediainit's ifmedia_set() finds a match, * does not panic, and ifm_cur is non-NULL for later jmphy_service() * calls (jmphy.c:138 dereferences mii->mii_media.ifm_cur). * * hw.jmsink_fixcheck=1 replays the same sequence WITH the fallback entry. */ static int jmsink_fixcheck(SYSCTL_HANDLER_ARGS) { struct ifmedia ifm2; int v = 0, error; error = sysctl_handle_opaque(oidp, &v, sizeof(v), req); if (error != 0 || req->newptr == NULL) return (error); kprintf("jmsink-fix: ifmedia_init + IFM_NONE fallback entry (the fixed jmphy path)\n"); ifmedia_init(&ifm2, 0, NULL, NULL); ifmedia_add(&ifm2, IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0, NULL); kprintf("jmsink-fix: calling ifmedia_set(IFM_ETHER|IFM_NONE) -- must NOT panic\n"); ifmedia_set(&ifm2, IFM_ETHER | IFM_NONE); kprintf("jmsink-fix: survived; ifm_cur=%p (non-NULL keeps jmphy_service safe)\n", ifm2.ifm_cur); ifmedia_removeall(&ifm2); return (0); } static int jmsink_modevent(module_t mod, int type, void *arg) { static struct sysctl_ctx_list ctx; switch (type) { case MOD_LOAD: sysctl_ctx_init(&ctx); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "jmsink_fire", CTLTYPE_INT | CTLFLAG_RW, 0, 0, jmsink_fire, "I", "fire the empty-list ifmedia_set"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "jmsink_fixcheck", CTLTYPE_INT | CTLFLAG_RW, 0, 0, jmsink_fixcheck, "I", "replay with the fixed fallback entry"); kprintf("jmsink: loaded; sysctl hw.jmsink_fire=1 to panic\n"); return (0); case MOD_UNLOAD: sysctl_ctx_free(&ctx); return (0); } return (0); } DEV_MODULE(jmsink, jmsink_modevent, NULL); |