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:
parent
0def474272
commit
f9e68779ee
1 changed files with 28 additions and 4 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue