The flip: PCI enumeration leaves the kernel (M19.3)
enumeratePci, addBars, pciConfigurationPtr, and the PciHeader struct are deleted; the kernel seeds only the host bridge, and the ring-3 pci-bus driver's reports are the sole source of PCI function nodes. The manager matches PCI drivers from reported identity, deduped by registered device id so a bus restart never double-spawns. The flip did its job by exposing a latent SMP race: ring-3 device_register made the broker table concurrent for the first time, and mmio_map read it lock-free — under load a torn resource length mapped hpet's window wrong (its user fault) and underflowed r.len-1 into a kernel integer-overflow panic. Fixed: the broker read in mmio_map (and claim) runs under the big kernel lock, the arithmetic rejects zero-length and wrapping windows cleanly, and pci-bus no longer registers unimplemented size-0 BARs. driver-restart hammered 6x, suite 55/55.
This commit is contained in:
@@ -50,17 +50,26 @@ fn driverFor(d: device.DeviceDescriptor) ?[]const u8 {
|
||||
/// pci-class.zig decodes.
|
||||
const xhci_pci_class: u64 = 0x0C_03_30;
|
||||
|
||||
/// The bus driver that serves a PCI function, or null. A machine can carry
|
||||
/// several identical controllers — one driver instance per device, the id as
|
||||
/// argv[1]. These drivers speak the protocol: a hello is expected.
|
||||
fn pciDriverFor(d: device.DeviceDescriptor) ?[]const u8 {
|
||||
if (d.class != @intFromEnum(device.DeviceClass.pci_device)) return null;
|
||||
return switch (d.pci_class) {
|
||||
/// The driver that serves a *reported* PCI function (M19.3: matching moved
|
||||
/// from the boot snapshot to the bus reports), or null. A machine can carry
|
||||
/// several identical controllers — one driver instance per reported device,
|
||||
/// its registered id as argv[1].
|
||||
fn pciDriverForIdentity(identity: u64) ?[]const u8 {
|
||||
return switch (identity) {
|
||||
xhci_pci_class => "usb-xhci-bus",
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// Whether some driver entry already serves registered device `device_id` —
|
||||
/// a re-report after a bus restart must not spawn a second instance.
|
||||
fn driverForDevice(device_id: u64) bool {
|
||||
for (&drivers) |*driver| {
|
||||
if (driver.used and driver.device_id == device_id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- supervision -------------------------------------------------------------
|
||||
|
||||
/// How long a protocol driver has to hello after its spawn.
|
||||
@@ -326,11 +335,8 @@ fn initialise(endpoint: runtime.ipc.Handle) bool {
|
||||
addDriver("pci-bus", descriptor.id, true);
|
||||
continue;
|
||||
}
|
||||
if (pciDriverFor(descriptor)) |driver_name| {
|
||||
matched += 1;
|
||||
addDriver(driver_name, descriptor.id, true);
|
||||
continue;
|
||||
}
|
||||
// PCI functions no longer appear in the boot snapshot (M19.3): the
|
||||
// pci-bus driver reports them, and onChildAdded matches from reports.
|
||||
const driver_name = driverFor(descriptor) orelse continue;
|
||||
matched += 1;
|
||||
// Skip a singleton that is already alive (the initial-ramdisk sweep test
|
||||
@@ -396,6 +402,14 @@ fn onChildAdded(message: []const u8, reply: []u8, sender: u32) usize {
|
||||
if (!addChild(report.parent, report.bus_address, report.identity, report.device_id, sender)) status = -1;
|
||||
writeLine("device-manager: child added (device {d} port {d}, identity {d}) by {s}\n", .{ report.parent, report.bus_address, report.identity, driver.name() });
|
||||
if (status == 0) publishEvent(message[0..protocol.child_added_size]);
|
||||
// Matching from reports (M19.3): a registered child whose identity
|
||||
// names a driver gets one, once — re-reports after a bus restart
|
||||
// dedupe on the registered id, exactly like the registrations do.
|
||||
if (status == 0 and report.device_id != protocol.no_device) {
|
||||
if (pciDriverForIdentity(report.identity)) |child_driver| {
|
||||
if (!driverForDevice(report.device_id)) addDriver(child_driver, report.device_id, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user