DF-4738 / cbb_busnum_alloc_demo.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 | /* * DF-4738 -- replica of the CardBus secondary-bus allocator in * sys/dev/pccard/pccbb/pccbb_pci.c:299,344-359 (cbb_pci_attach). * * Replicated verbatim (DEVPRINTF dropped): the static curr_bus_number * shared across every cbb instance, and the renumbering block. * * Demonstrates, deterministically, on fixture inputs that a real BIOS * can produce: * (1) COLLISION -- firmware already assigned bus 2 to another bridge * (e.g. an AGP/PCIe root port); a cbb socket whose SECBUS was left * 0 by firmware is renumbered onto that same bus 2. No check of * bus numbers already owned anywhere in the tree exists. * (2) WRAP -- after 126 sockets (252 bus numbers), curr_bus_number * exceeds 255 and truncates into the u_int8_t secbus/subbus * (pccbbvar.h:68-69), yielding secbus 0 / duplicate 0x100 values * written to PCIR_SECBUS_2/PCIR_SUBBUS_2. No free-number check * exists. */ #include <stdio.h> #include <stdint.h> /* pccbb_pci.c:299 */ static int curr_bus_number = 2; struct cbb_fixture { const char *name; int secbus_reg; /* PCIR_SECBUS_2 as read */ int subbus_reg; /* PCIR_SUBBUS_2 as read */ int pribus_reg; /* PCIR_PRIBUS_2 as read */ int pribus_actual; /* pcib_get_bus(parent) */ uint8_t secbus; /* cbbvar.h:68 u_int8_t */ uint8_t subbus; /* cbbvar.h:69 u_int8_t */ }; /* verbatim pccbb_pci.c:343-359 */ static void cbb_pci_attach_renumber(struct cbb_fixture *sc) { int pribus; pribus = sc->pribus_reg; if (sc->secbus_reg == 0 || sc->pribus_actual != pribus) { if (curr_bus_number <= sc->pribus_actual) curr_bus_number = sc->pribus_actual + 1; if (pribus != sc->pribus_actual) { /* pci_write_config(brdev, PCIR_PRIBUS_2, pribus) */ } sc->secbus_reg = curr_bus_number++; sc->subbus_reg = curr_bus_number++; /* pci_write_config(brdev, PCIR_SECBUS_2 / SUBBUS_2, 1) */ } sc->secbus = (uint8_t)sc->secbus_reg; /* softc fields are u_int8_t */ sc->subbus = (uint8_t)sc->subbus_reg; } /* a firmware-configured non-cbb bridge (AGP/PCIe root port) */ static struct cbb_fixture pcie_root = { "pcie0 (firmware-configured)", /*sec*/2, /*sub*/2, /*pri*/0, 0, 0, 0 }; int main(void) { int i; int zeroed = 0; /* * Case 1: ordinary laptop -- firmware gave the PCIe root port * secondary bus 2, but left the CardBus socket unprogrammed * (SECBUS=0), a state the in-tree comment anticipates. */ printf("before: %s owns secondary bus %d\n", pcie_root.name, pcie_root.secbus_reg); struct cbb_fixture cbb0 = { "cbb0 (SECBUS=0 from firmware)", 0, 0, 0, 0, 0, 0 }; cbb_pci_attach_renumber(&cbb0); printf("after : %s renumbered to secbus=%d subbus=%d\n", cbb0.name, cbb0.secbus, cbb0.subbus); if (cbb0.secbus == pcie_root.secbus_reg) printf("=> COLLISION: two bridges now own bus %d; type-1 config\n" " cycles for the CardBus card are also claimed by %s\n" " (config reads/writes can hit an unrelated device).\n", cbb0.secbus, pcie_root.name); /* * Case 2: exhaust the 8-bit space -- attach more sockets. */ struct cbb_fixture extra; extra.pribus_actual = 0; for (i = 0; i < 128; i++) { extra.secbus_reg = 0; extra.subbus_reg = 0; extra.pribus_reg = 0; cbb_pci_attach_renumber(&extra); if (extra.secbus_reg >= 256) printf("socket #%d: secbus_reg=%d -> u_int8_t secbus=%d, " "subbus_reg=%d -> u_int8_t subbus=%d\n", i + 1, extra.secbus_reg, extra.secbus, extra.subbus_reg, extra.subbus); if (extra.secbus_reg == 256) zeroed = 1; } printf("\ncurr_bus_number=%d after %d sockets: no >255 check exists;\n", curr_bus_number, i); printf("socket #127 got secbus_reg=256 -> u_int8_t secbus=0: the very\n" "'unconfigured' sentinel (secbus==0) that pccbb_pci.c:345 treats as\n" "invalid -- re-triggers renumbering on resume/re-probe and aliases\n" "the host bus (bus 0) for CardBus config cycles.\n"); return (cbb0.secbus == 2 && zeroed) ? 0 : 1; } |