;
; ****************************************************************************
+%define DEBUG_TRACERS ; Uncomment to get debugging tracers
+
+%ifdef DEBUG_TRACERS
+
+%macro TRACER 1
+ call debug_tracer
+ db %1
+%endmacro
+
+%else ; DEBUG_TRACERS
+
+%macro TRACER 1
+%endmacro
+
+%endif ; DEBUG_TRACERS
+
org 0h
%define SECTORSIZE_LG2 9 ; log2(sector size)
pop dx
js .nomatch ; If SF=0, we have a class match here
jz .our_drive ; If ZF=1, we have an exact match
+ cmp ah,08h ; Is it Get Drive Parameters?
+ je .our_drive ; If so always handle for our own class
cmp dl,[cs:DriveNo]
jb .nomatch ; Drive < Our drive
dec dl ; Drive > Our drive, adjust drive #
mov ax,[SavedAX]
pushad
mov bp,sp ; Point BP to the entry stack frame
+ TRACER 'F'
; Note: AH == P_AH here
cmp ah,Int13FuncsMax
- jae Invalid
+ jae Invalid_jump
xor al,al ; AL = 0 is standard entry condition
mov di,ax
shr di,7 ; Convert AH to an offset in DI
Done: ; Standard routine for return
mov P_AX,ax
DoneWeird:
+ TRACER 'D'
mov [LastStatus],ah
and ah,ah
Reset:
; Reset affects multiple drives, so we need to pass it on
+ TRACER 'R'
mov [LastStatus],al ; Clear the status (AL = 0)
pop ax ; Drop return address
popad ; Restore all registers
and dl,80h ; Clear all but the type bit
jmp far [cs:OldInt13]
+
Invalid:
- mov ax,0100h ; Unsupported function
- ret
+ pop dx ; Drop return address
+Invalid_jump:
+ TRACER 'I'
+ mov ah,01h ; Unsupported function
+ jmp short Done
GetDriveType:
mov ah,[DriveNo]
ret
GetParms:
- ; We need to get the "number of drives" from the BIOS
- mov dl,P_DL
- inc dl ; The drive whose number we're stealing
- mov ah,08h
- int 13h
- inc dl ; Add ourselves to the count
- mov P_DL,dl ; Drive count
- mov P_DI,di ; Steal the diskette parameter table if applicable
- mov ax,es
+ ; This gets invoked even for other drives, so that
+ ; we can modify the drive count on return
+ TRACER 'G'
+ mov dx,P_DX ; The drive whose number we're stealing
+ cmp dl,[DriveNo]
+ jb .belowdrive
+ ja .abovedrive
+ TRACER 'M'
+ mov dl,[DriveCnt] ; Cached data
+ mov P_DL,dl
+ test byte [DriveNo],80h
+ jnz .hd
+ mov di,[BPT]
+ mov P_DI,di
+ mov ax,[BPT+2]
mov P_ES,ax
mov bl,[DriveType]
mov P_BL,bl
+.hd:
mov ax,[Cylinders]
dec ax ; We report the highest #, not the count
- or ah,[Sectors]
xchg al,ah
+ shl al,6
+ or al,[Sectors]
mov P_CX,ax
- mov al,[Heads]
- dec al
+ mov ax,[Heads]
+ dec ax
mov P_DH,al
xor ax,ax
ret
+
+ ; If another disk, just mangle DL on return
+.abovedrive:
+ TRACER 'A'
+ dec dl ; Adjust drive # to what the BIOS believes
+.belowdrive:
+ TRACER 'B'
+ mov di,P_DI
+ mov ax,P_ES
+ mov es,ax
+ mov bx,P_BX
+ mov cx,P_CX
+ mov ax,P_AX
+ pushf
+ call far [OldInt13]
+ inc dl ; Add ourselves to the count
+ mov P_AX,ax
+ mov P_BX,bx
+ mov P_CX,cx
+ mov P_DX,dx
+ mov P_DI,di
+ mov cx,es
+ mov P_ES,cx
+ TRACER 'R'
+ ret
; Set up registers as for a "Read", and compares against disk size
setup_regs:
ret
.overrun: pop ax ; Drop setup_regs return address
- mov ax,0400h ; Sector not found
- ret
+ mov ax,0200h ; Missing address mark
+ ret ; Return to Done
int15_e820:
cmp edx,534D4150h ; "SMAP"
pop eax
ret
+%ifdef DEBUG_TRACERS
+debug_tracer: pushad
+ pushfd
+ mov bp,sp
+ mov bx,[bp+9*4]
+ mov al,[cs:bx]
+ inc word [bp+9*4]
+ mov ah,0Eh
+ mov bx,7
+ int 10h
+ popfd
+ popad
+ ret
+%endif
+
section .data
- alignb 8
+ alignb 2
Int13Funcs dw Reset ; 00h - RESET
dw GetStatus ; 01h - GET STATUS
dw Read ; 02h - READ
DriveNo db 0 ; Our drive number
DriveType db 0 ; Our drive type (floppies)
+DriveCnt db 0 ; Drive count (from the BIOS)
+ db 0 ; Pad
+BPT dd 0 ; BIOS parameter table pointer (floppies)
MyStack dw 0 ; Offset of stack
uint8_t driveno;
uint8_t drivetype;
+ uint8_t drivecnt;
+ uint8_t _pad1;
+
+ uint16_t bpt_offs, bpt_seg;
uint16_t mystack;
};
+/* The Disk Parameter Table is required on hard disks */
+struct dpt {
+ uint16_t max_cyl; /* Max cylinder */
+ uint8_t max_head; /* Max head */
+ uint8_t junk1[5]; /* Obsolete junk, leave at zero */
+ uint8_t ctrl; /* Control byte */
+ uint8_t junk2[7]; /* More obsolete junk */
+};
+
/* This is the header in the boot sector/setup area */
struct setup_header {
char cmdline[0x1f1];
/* Addresses in the zero page */
#define BIOS_INT13 (0x13*4) /* INT 13h vector */
-#define BIOS_INT15 (0x15*4) /* INT 13h vector */
+#define BIOS_INT15 (0x15*4) /* INT 15h vector */
+#define BIOS_INT41 (0x41*4) /* INT 41h vector */
+#define BIOS_INT46 (0x46*4) /* INT 46h vector */
#define BIOS_BASEMEM 0x413 /* Amount of DOS memory */
+#define BIOS_EQUIP 0x410 /* BIOS equipment list */
+#define BIOS_HD_COUNT 0x475 /* Number of hard drives present */
/*
* Routine to seek for a command-line item and return a pointer
"D" (0)
: "esi", "edi", "ecx");
+ /* Query drive parameters of this type */
+ {
+ uint16_t bpt_es, bpt_di;
+ uint8_t cf, dl;
+
+ asm volatile("pushw %%es ; "
+ "xorw %1,%1 ; "
+ "movw %1,%%es ; "
+ "movb $0x08,%%ah ; "
+ "int $0x13 ; "
+ "setc %2 ; "
+ "movw %%es,%0 ;"
+ "popw %%es"
+ : "=a" (bpt_es), "=D" (bpt_di),
+ "=c" (cf), "=d" (dl)
+ : "d" (geometry->driveno & 0x80)
+ : "esi", "ebx", "ebp");
+
+ if ( cf ) {
+ pptr->drivecnt = 1;
+ pptr->bpt_offs = pptr->bpt_seg = 0;
+ } else {
+ pptr->drivecnt = dl+1;
+ pptr->bpt_offs = bpt_di;
+ pptr->bpt_seg = bpt_es;
+ }
+ }
+
/* Install the interrupt handlers */
printf("old: int13 = %08x int15 = %08x\n",
rdz_32(BIOS_INT13), rdz_32(BIOS_INT15));
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 ) {
+ /* Update BIOS hard disk count */
+ wrz_8(BIOS_HD_COUNT, rdz_8(BIOS_HD_COUNT)+1);
+ } else {
+ /* Update BIOS floppy disk count */
+ uint16_t equip = rdz_16(BIOS_EQUIP);
+ if ( equip & 1 ) {
+ if ( (equip & (3 << 6)) != (3 << 6) ) {
+ equip += (1 << 6);
+ }
+ } else {
+ equip |= 1;
+ equip &= ~(3 << 6);
+ }
+ wrz_16(BIOS_EQUIP, equip);
+ }
+
/* Reboot into the new "disk" */
asm volatile("pushw %%es ; "
"xorw %%cx,%%cx ; "