summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2008-07-03 15:22:39 -0700
committerH. Peter Anvin <hpa@zytor.com>2008-07-03 15:22:39 -0700
commit8e5db045c60ce25a9eb65a1803d47be4002a3e17 (patch)
tree8972e976d9dcf866cbbe2f10950d3699aacdd171
parentb941fb60dcf169bea3769466238a63b7eb15d739 (diff)
downloadsyslinux-8e5db045c60ce25a9eb65a1803d47be4002a3e17.tar.gz
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.
-rw-r--r--memdisk/memdisk.asm14
-rw-r--r--memdisk/memdisk.h2
-rw-r--r--memdisk/setup.c60
3 files changed, 61 insertions, 15 deletions
diff --git a/memdisk/memdisk.asm b/memdisk/memdisk.asm
index f175ef43..15d662d2 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 bb2057de..615e3d1e 100644
--- a/memdisk/memdisk.h
+++ b/memdisk/memdisk.h
@@ -19,6 +19,8 @@
#ifndef MEMDISK_H
#define MEMDISK_H
+#include <stddef.h>
+
/* We use the com32 interface for calling 16-bit code */
#include <com32.h>
diff --git a/memdisk/setup.c b/memdisk/setup.c
index ba02582f..32dd8ed5 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(&regs, 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, &regs, &regs);
- 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... ");