summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhpa <hpa>2001-12-14 22:41:55 +0000
committerhpa <hpa>2001-12-14 22:41:55 +0000
commit4d022320084eabdc70607643dff9a1822ca92081 (patch)
treee6b65be78c22d8b77ff405654f694c31272cd840
parentb8dbb462b18fbae9ee5577904a45029cb80d16bd (diff)
downloadsyslinux-4d022320084eabdc70607643dff9a1822ca92081.tar.gz
Be even more anal...
-rw-r--r--memdisk/memdisk.asm112
-rw-r--r--memdisk/setup.c66
2 files changed, 159 insertions, 19 deletions
diff --git a/memdisk/memdisk.asm b/memdisk/memdisk.asm
index 9bc453d9..610af31d 100644
--- a/memdisk/memdisk.asm
+++ b/memdisk/memdisk.asm
@@ -17,6 +17,22 @@
;
; ****************************************************************************
+%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)
@@ -64,6 +80,8 @@ Int13Start:
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 #
@@ -85,9 +103,10 @@ Int13Start:
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
@@ -96,6 +115,7 @@ Int13Start:
Done: ; Standard routine for return
mov P_AX,ax
DoneWeird:
+ TRACER 'D'
mov [LastStatus],ah
and ah,ah
@@ -112,6 +132,7 @@ DoneWeird:
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
@@ -121,9 +142,13 @@ Reset:
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]
@@ -176,28 +201,61 @@ success:
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:
@@ -239,8 +297,8 @@ 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"
@@ -372,8 +430,23 @@ bcopy:
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
@@ -434,6 +507,9 @@ OldDosMem dw 0 ; Old position of DOS mem end
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
diff --git a/memdisk/setup.c b/memdisk/setup.c
index 530dc0c7..eff2d47a 100644
--- a/memdisk/setup.c
+++ b/memdisk/setup.c
@@ -45,10 +45,23 @@ struct patch_area {
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];
@@ -183,8 +196,12 @@ rdz_32(uint32_t addr)
/* 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
@@ -514,6 +531,34 @@ uint32_t setup(void)
"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));
@@ -524,6 +569,25 @@ uint32_t setup(void)
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 ; "