ide: idewait spun for a minute on any machine with no legacy drive

The bound was 20,000,000 iterations, on the reasoning that a real drive
answers in microseconds so only an empty channel could reach the end. True,
and it misses what an iteration costs: every read here is a port access, and
under a hypervisor a port access is a VM exit at a microsecond or two.

Twenty million of those is a minute of the machine apparently doing nothing,
on every boot, on any machine with nothing on the primary IDE channel -- which
is every machine built in the last decade, where storage is AHCI or NVMe and
the legacy ports answer nobody. Booting the ISO looked like a hang for exactly
that reason: the line after "time:" took longer than anyone waits.

Bounded by time now, one second: four orders of magnitude more than a drive
needs, and short enough that an absent one costs nothing. "ide: no drive on
the primary channel" prints immediately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
This commit is contained in:
Nexoniarz 2026-09-13 14:43:35 +02:00
commit f9e68779ee

View file

@ -55,22 +55,46 @@ static void idestart(struct buf*);
// dead machine right after the VGA banner. That is not an exotic
// configuration: it is every CD boot, and most hardware newer than IDE.
//
// The bound is deliberately enormous. A real drive answers in microseconds;
// this only expires when there is nothing there at all.
// Bounded by *time*, not by a count of port reads.
//
// The bound used to be 20,000,000 iterations, on the reasoning that a real
// drive answers in microseconds so only an empty channel could reach the end.
// True, and it misses what an iteration costs: every `inb` here is a port
// access, and under a hypervisor a port access is a VM exit at a microsecond
// or two. Twenty million of them is a minute of the machine apparently doing
// nothing, on every boot, on any machine with no drive on the primary channel.
//
// That is not a rare configuration -- it is every machine built in the last
// decade, where storage is AHCI or NVMe and the legacy ports answer nothing.
// A SchOS booted from a USB stick on real hardware spent that minute staring
// at an empty ISA port before it printed its next line.
//
// One second is four orders of magnitude more than a drive needs and short
// enough that an absent one costs nothing worth measuring.
static int
idewait(int checkerr)
{
uint64 deadline = tsc_hz ? rdtsc() + tsc_hz : 0;
int r = 0;
for(int i = 0; i < 20000000; i++){
for(;;){
r = inb(0x1f7);
if((r & (IDE_BSY|IDE_DRDY)) == IDE_DRDY){
if(checkerr && (r & (IDE_DF|IDE_ERR)) != 0)
return -1;
return 0;
}
// No calibrated TSC yet (which cannot happen from ideinit, but this
// function has other callers and one of them may move): fall back to a
// count, small enough not to cost a minute.
if (deadline == 0) {
static int spins;
if (++spins > 100000) { spins = 0; return -1; }
continue;
}
if (rdtsc() >= deadline)
return -1;
}
return -1;
}
static void