kernel: the device table has no ceiling; a runaway is charged to whoever caused it
maximum_devices = 64 is gone. It was a guess about someone else's computer, and because it was shared, one driver's enumeration starved every other — which is how an AMD Ryzen booted with a working display, no USB and no storage. The table now grows from the kernel heap. It was always built after heap.init; nothing ever prevented this except it having been written static first. What replaces it is an allowance charged to the registrar, so a driver looping device_register exhausts its own and every other driver carries on. It is declared as what it is — a runaway detector, NOT a security boundary. A quota generous enough never to bite a real machine is still generous enough to be unpleasant, and it is not trying to be the defence; delegation is. What this catches is a legitimate driver in a loop, early, attributably, and without collateral. Reaching 4096 is a bug report, not a tuning request. The initial block is 8, deliberately small. Sizing it for a typical machine would mean the growth path never ran on the hardware we test on and only woke up on someone else's larger machine — the exact failure shape this track exists to stop. At 8 it grows several times every boot; disabling growth now fails the suite with the HPET not fitting, which is the Ryzen failure in miniature. The comptime coupling assert added earlier fired, and was right to. confined (one slot per device id) and domains (the IOMMU's own translation pool) were sized by the same constant only because device ids happened to stop at 64 too. Two unrelated quantities: confined now grows with the device table, while maximum_domains stays as the hardware's number — both VT-d and AMD-Vi report how many domains they support, and reading it is phase 4. The assert existed for exactly this and did its job. Suite 118/118.
This commit is contained in:
@@ -4020,6 +4020,17 @@ fn containmentTest() void {
|
||||
const still_capped = if (devices_broker.register(parent_id, me, &novel)) |_| false else |err| err == error.TooManyChildren;
|
||||
check("a full parent still refuses a new child", still_capped);
|
||||
|
||||
// The table itself has no ceiling: it grows. The old `maximum_devices = 64` was a
|
||||
// guess about someone else's computer, and one driver's enumeration starved every
|
||||
// other — which is how a Ryzen booted with no USB and no storage. What bounds a
|
||||
// runaway now is an allowance charged to the registrar, so the damage stays with
|
||||
// whoever caused it (docs/os-development/device-authority.md).
|
||||
// The table grows: it starts at 8 entries and this boot holds well past that, so
|
||||
// the growth path runs every time rather than lying dormant until someone else's
|
||||
// larger machine finds it — which is how the old ceiling stayed invisible.
|
||||
const held = devices_broker.enumerate(&buffer);
|
||||
check("the table grew beyond its initial block", held > 8);
|
||||
|
||||
result();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user