Notes on BIOS usage ------------------- - DOS (including 6.22/7.1) does not need INT 15h or INT 1Ah. Most other operating systems require INT 15h to detect installed memory. - OS/2 (WSeB/MCP/ACP) and Windows 98 SE are some of the very few operating systems which use the El Torito floppy emulation. - NetWare 5.1 is one of the *extremely* few users of El Torito hard disk emulation. - Keystroke check (INT 16h, fn 01h/10h) always enables interrupts on return. DOS POWER.EXE depends on that in some situations. - MS-DOS 6.2/V is a rare user of the INT 15h keyboard intercept routines. - Some software uses the model byte at F000:FFFE to determine the system type (PC-DOS 3.0, Norton Utilities 8). Other software first tries INT 15h, fn C0h instead (PC-DOS 3.1, MSD). - DOS 4.01 (both IBM and Microsoft) calls INT 13h to read from disk with less than 100 bytes of stack space early in the boot sequence. - Very few guests use the 32-bit PCI BIOS interface. One is OS/2 (but falls back), another is Etherboot. - OS/2 is the only known guest which can run the 16-bit PCI BIOS in protected mode (but only if the 32-bit PCI BIOS is unavailable). - NetWare 6.x is the only known guest which uses the PCI BIOS service to read the IRQ routing table. - Any disk reads which use bus-master DMA (AHCI, IDE BM) must use VDS (Virtual DMA Services) when present. Otherwise any reads/writes when the real mode addresses don't map directly to physical addresses will fail horribly. DOS 6.x with EMM386 is a good testcase (esp. loading drivers into UMBs). - Many older OSes (especially UNIX based) require the FDPT to contain physical ATA disk geometry; for that reason, disks smaller than ~500MB are easiest to use. Otherwise a "large" BIOS disk option would be required. - Some really old OSes (Xenix circa 1986-7) do not understand the EBDA idea and clear the memory. For those, the FDPT must be in the BIOS ROM area, or the OS will destroy it (even when it's at 0:300 in the IVT). - Windows NT (including XP) uses INT 13h/08h to obtain the DPT for each floppy drive. NT assumes a 13-byte DPT which includes the number of tracks. NT will refuse to read more tracks than the DPT specifies and formats as many tracks as the DPT specifies. - Windows 98 SE boot CD uses 32-bit registers in real mode and will fail in mysterious ways if BIOS trashes high bits of EAX (and likely others). - PC DOS 6.x/7.x QCONFIG is a rare user of INT 16h fn 0Ah (read keyboard ID). - DOS POWER.EXE uses the real mode APM interface, OS/2 APM.SYS uses the 16-bit protected mode APM interface, and Windows 9x uses the 32-bit protected mode APM interface. - Windows 98 is one of the few APM 1.2 users; Windows 95 uses APM 1.1, while newer systems prefer ACPI. - QNX4 calls 16-bit protected-mode PCI BIOS in an environment where ESP is 16-bit but SS is a 32-bit stack segment. In such environments, using the ENTER/LEAVE sequence is fatal if the high word of EBP is non-zero (which it will be with QNX 4.25). LEAVE propagates the high word of EBP into ESP with fatal consequences. - Plan 9 also runs 16-bit code with a 32-bit stack segment, except Plan 9 thinks it counts as real mode. Same ENTER/LEAVE problem as above. - AIX 1.3 is a rare user of INT 15h/89h (switch to protected mode) service. - IBM OS/2 1.0/1.1 (but not other versions!) attempt to execute a 286 LOADALL instruction. LOADALL must be emulated for OS/2 to work properly. HIMEM.SYS version 2.03 and later also contains 286 LOADALL code but this will not be executed on 386+ processors. Notes on BIOS implementation ---------------------------- - To return values from functions not declared as __interrupt, the arguments may need to be declared volatile (not ideal, but does the job). - The way the POST code selectively clears or doesn't clear memory is extremely suspect and will need reworking. - Need to review string routines wrt direction flag (should be OK now). - Need to review CMOS access wrt interrupts (possible index reg change by an interrupt handler). - The POST code zeroes the entire BDA, and then various bits zero specific parts of the BDA again. That's a waste of time. - After a reset, all interrupts are unmasked. Not sure if that's OK. - BCC mishandles the following (where buf is an uint8_t array): lba=buf[0x2B]*0x1000000+buf[0x2A]*0x10000+buf[0x29]*0x100+buf[0x28]; The buf[x]*100 expression should end up being of type signed int, which causes the sign to be incorrectly propagated. BCC incorrectly keeps the type unsigned. - The PCI BIOS services are implemented in C, compiled twice as 16-bit and 32-bit code. This reduces the development effort and significantly lowers the risk of discrepancies between 16-bit and 32-bit implementation. Care must be taken because the 16-bit implementation can be executed in both real and protected mode. - APM can be in theory implemented only once for real, 16-bit protected and 32-bit protected mode. Unfortunately this is very inconvenient in C since the default stack size changes between 16-bit and 32-bit callers. Therefore real mode APM (which supports most functions) is implemented in C and protected-mode APM is written in assembler for both 16-bit and 32-bit calls, with a small 32->16 thunk. - The -of switch can be used to avoid generating ENTER/LEAVE instructions. This appears to be an undocumented and perhaps unintentional side effect. Code size notes (code as of 7/6/2011): The following values are the size of the _TEXT segment, i.e. only C code; data defined in C is not included, neither are assembly modules. Options: Size (hex): -------- ----------- -0 -zu -s -oas -ecc 631A -3 -zu -s -oas -ecc 5C1E -0 -zu -s -oas 578A -3 -zu -s -oas 5452 Both generating 386 code and using register-based calling convention for internal functions brings significant size savings (15% when combined).