From 8e5db045c60ce25a9eb65a1803d47be4002a3e17 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 3 Jul 2008 15:22:39 -0700 Subject: [PATCH] memdisk: install a DPT if needed in INT 1Eh; better zero-drive detection Per the Interrupt list, treat INT 13 08 returning with CL=0 as a failure, meaning single drive only. If we find ourselves the only floppy drive, install a DPT into INT 1Eh. This appears to be needed for PC-DOS 7.0 to boot. This can be overridden with the "nodpt" option, and forced with the "dpt" option. --- memdisk/memdisk.asm | 14 +++++++++++-- memdisk/memdisk.h | 2 ++ memdisk/setup.c | 60 +++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/memdisk/memdisk.asm b/memdisk/memdisk.asm index f175ef4..15d662d 100644 --- a/memdisk/memdisk.asm +++ b/memdisk/memdisk.asm @@ -917,7 +917,7 @@ Mover_dummy2: dd 0, 0, 0, 0 ; More space for the BIOS alignb 4, db 0 MemDisk_Info equ $ ; Pointed to by installation check -MDI_Bytes dw 27 ; Total bytes in MDI structure +MDI_Bytes dw MDI_Len ; Total bytes in MDI structure MDI_Version db VER_MINOR, VER_MAJOR ; MEMDISK version PatchArea equ $ ; This gets filled in by the installer @@ -931,10 +931,18 @@ OldInt15 dd 0 ; INT 15h in chain OldDosMem dw 0 ; Old position of DOS mem end BootLoaderID db 0 ; Boot loader ID from header + db 0 ; pad + +DPT_ptr dw 0 ; If nonzero, pointer to DPT + ; Original DPT pointer follows + +MDI_Len equ $-MemDisk_Info + ; ---- MDI structure ends here --- Int13MaxFunc db Int13FuncsCnt-1 ; Max INT 13h function (to disable EDD) + db 0 ; pad - db 0, 0 ; pad + dw 0 ; pad MemInt1588 dw 0 ; 1MB-65MB memory amount (1K) Cylinders dw 0 ; Cylinder count @@ -954,6 +962,8 @@ MyStack dw 0 ; Offset of stack StatusPtr dw 0 ; Where to save status (zeroseg ptr) DPT times 16 db 0 ; BIOS parameter table pointer (floppies) +OldInt1E dd 0 ; Previous INT 1E pointer (DPT) + %if EDD EDD_DPT: .length dw 30 diff --git a/memdisk/memdisk.h b/memdisk/memdisk.h index bb2057d..615e3d1 100644 --- a/memdisk/memdisk.h +++ b/memdisk/memdisk.h @@ -19,6 +19,8 @@ #ifndef MEMDISK_H #define MEMDISK_H +#include + /* We use the com32 interface for calling 16-bit code */ #include diff --git a/memdisk/setup.c b/memdisk/setup.c index ba02582..32dd8ed 100644 --- a/memdisk/setup.c +++ b/memdisk/setup.c @@ -55,7 +55,11 @@ typedef union { uint8_t ffill; /* Format fill byte */ uint8_t settle; /* Head settle time (ms) */ uint8_t mstart; /* Motor start time */ - uint8_t _pad1; /* Padding */ + uint8_t maxtrack; /* Maximum track number */ + + uint8_t rate; /* Data transfer rate */ + uint8_t cmos; /* CMOS type */ + uint8_t pad[2]; uint32_t old_fd_dpt; /* Extension: pointer to old INT 1Eh */ } fd; @@ -83,10 +87,15 @@ struct patch_area { uint16_t olddosmem; uint8_t bootloaderid; + uint8_t _pad1; + + uint16_t dpt_ptr; + /* End of the official MemDisk_Info */ uint8_t maxint13func; #define MAXINT13_NOEDD 0x16 + uint8_t _pad2; - uint8_t _pad[2]; + uint16_t _pad3; uint16_t memint1588; uint16_t cylinders; @@ -597,6 +606,7 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce) uint32_t ramdisk_image, ramdisk_size; int bios_drives; int do_edd = -1; /* -1 = default, 0 = no, 1 = yes */ + int no_bpt; /* No valid BPT presented */ /* Set up global variables */ syscall = cs_syscall; @@ -714,6 +724,8 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce) pptr->dpt.fd.ffill = 0xf6; pptr->dpt.fd.settle = 0x0f; pptr->dpt.fd.mstart = 0x05; + pptr->dpt.fd.maxtrack = geometry->c-1; + pptr->dpt.fd.cmos = geometry->type > 5 ? 5 : geometry->type; pptr->dpt.fd.old_fd_dpt = rdz_32(BIOS_INT1E); } @@ -798,6 +810,7 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce) bios_drives = 0; pptr->drivecnt = 0; pptr->oldint13 = driverptr+hptr->iret_offs; + no_bpt = 1; } else { /* Query drive parameters of this type */ memset(®s, 0, sizeof regs); @@ -806,13 +819,17 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce) regs.edx.b[0] = geometry->driveno & 0x80; syscall(0x13, ®s, ®s); - if ( regs.eflags.l & 1 ) { + /* Note: per suggestion from the Interrupt List, consider + INT 13 08 to have failed if the sector count in CL is zero. */ + if ((regs.eflags.l & 1) || !(regs.ecx.b[0] & 0x3f)) { printf("INT 13 08: Failure, assuming this is the only drive\n"); pptr->drivecnt = 0; + no_bpt = 1; } else { printf("INT 13 08: Success, count = %u, BPT = %04x:%04x\n", regs.edx.b[0], regs.es, regs.edi.w[0]); pptr->drivecnt = regs.edx.b[0]; + no_bpt = !(regs.es|regs.edi.w[0]); } /* Compare what INT 13h returned with the appropriate equipment byte */ @@ -848,21 +865,18 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce) /* Copy driver followed by E820 table followed by command line */ { unsigned char *dpp = (unsigned char *)(driverseg << 4); + + /* Adjust these pointers to point to the installed image */ + /* Careful about the order here... the image isn't copied yet! */ + pptr = (struct patch_area *)(dpp + hptr->patch_offs); + hptr = (struct memdisk_header *)dpp; + + /* Actually copy to low memory */ dpp = memcpy_endptr(dpp, &_binary_memdisk_bin_start, bin_size); dpp = memcpy_endptr(dpp, ranges, (nranges+1)*sizeof(ranges[0])); dpp = memcpy_endptr(dpp, shdr->cmdline, cmdlinelen+1); } - /* Install the interrupt handlers */ - printf("old: int13 = %08x int15 = %08x\n", - rdz_32(BIOS_INT13), rdz_32(BIOS_INT15)); - - wrz_32(BIOS_INT13, driverptr+hptr->int13_offs); - wrz_32(BIOS_INT15, driverptr+hptr->int15_offs); - - printf("new: int13 = %08x int15 = %08x\n", - rdz_32(BIOS_INT13), rdz_32(BIOS_INT15)); - /* Update various BIOS magic data areas (gotta love this shit) */ if ( geometry->driveno & 0x80 ) { @@ -886,8 +900,28 @@ __cdecl void setup(__cdecl syscall_t cs_syscall, void *cs_bounce) equip |= ((nflop-1) << 6) | 0x01; wrz_8(BIOS_EQUIP, equip); + + /* Install DPT pointer if this was the only floppy */ + if (getcmditem("dpt") != CMD_NOTFOUND || + ((nflop == 1 || no_bpt) + && getcmditem("nodpt") == CMD_NOTFOUND)) { + /* Do install a replacement DPT into INT 1Eh */ + pptr->dpt_ptr = hptr->patch_offs + offsetof(struct patch_area, dpt); + } } + /* Install the interrupt handlers */ + printf("old: int13 = %08x int15 = %08x int1e = %08x\n", + rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E)); + + wrz_32(BIOS_INT13, driverptr+hptr->int13_offs); + wrz_32(BIOS_INT15, driverptr+hptr->int15_offs); + if (pptr->dpt_ptr) + wrz_32(BIOS_INT1E, driverptr+pptr->dpt_ptr); + + printf("new: int13 = %08x int15 = %08x int1e = %08x\n", + rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E)); + /* Reboot into the new "disk"; this is also a test for the interrupt hooks */ puts("Loading boot sector... "); -- 2.7.4