--- /dev/null
+/*
+ * misc/int13sniff.S
+ *
+ * Copyright (C) 2000
+ * Partition Surprise Team <surprise-dev@lists.sourceforge.net>
+ *
+ * $Id: int13sniff.S,v 1.4 2001/02/13 00:47:18 kratochvil Exp $
+ */
+
+
+/*
+ *
+ * Sniffer for INT13 calls
+ *
+ * Prepare your floppy and reboot from it with 0x80 disk for boot-sniffing:
+ * ANY DATA ON YOUR FLOPPY (/dev/fd0) WILL BE ERASED BY THIS COMMAND!
+ *
+ * make int13sniff.fd0
+ *
+ *
+ */
+
+
+/* !!! All defines below must be COMMENTED-OUT !
+ * !!! Define to value 0 has no effect.
+ */
+
+/* Enable of normal screen dump output.
+ * You can probably never need to undefine it, only if it severly
+ * harms some needed (fullscreen) application display output.
+ */
+#define SCREEN_PRINT 1
+
+/* Enable (if defined) dump output to all serials found
+ */
+#define SERIAL_BAUDRATE 9600
+
+/* Enable to refuse dumping output to port without DSR active
+ * - pro: doesn't get slow by dumping to not-connected ports
+ * - con: some cables may not have DSR (DTR<->DSR wiring would be sufficient)
+ */
+#define SERIAL_REQUIRE_DSR
+
+/* Enable to dump all messages back to floppy
+ * - con: message output is slowed down a bit
+ * WARNING: some BIOSes fail to report geometry (INT 0x13/AH=0x08) for HDD!
+ */
+#define OUTPUT_STORE_DISK 0x00
+
+/* Linear sector offset where to start writing buffer sectors
+ * If undefined, it is calculated to be the last sector of "int13sniff.bin".
+#define OUTPUT_STORE_ADDRESS -1
+ */
+
+/* Stack size to reserve in the top-memory area
+ * WARNING: Due to SECTORS_LEN reading, this value MUST be always >=
+ * than the sector size (0x200)!
+ */
+#define STACKSIZE_TOP 0x200
+
+/* Maintainers: Disable occupying of any (0x13 & 0x18) interrupt vectors
+#define DISABLE_SNIFF 1
+ */
+
+/* Maintainers: Disable .org macroinstructions: ONLY FOR compilation tuning!
+ * - image produced doen't have any functionality!
+#define DISABLE_ORG 1
+ */
+
+
+/* Internal defines */
+#define SERIAL_SENDWAIT 16 /* multiplied by 0x10000, Linux kernel has ~15 (looping 1E6 times) */
+#define SERIAL_LCR_INIT (UART_LCR_WLEN8) /* 8N1, no DLAB */
+#define SERIAL_MCR_INIT (UART_MCR_DTR | UART_MCR_RTS) /* we are RTSed! */
+#define MEM_KBYTES 0x413 /* BIOS variable */
+#define PORTADDR_BASE 0x400 /* BIOS variable */
+#define SECTOR2_MAGIC 0xEFBE
+#define SERIAL_DIVISOR (115200/SERIAL_BAUDRATE)
+#define OUTPUT_STORE_WRITE_RETRIES 5 /* how many times to try Write16 & ResetDisk sequence */
+#define OUTPUT_STORE_EOF 26
+
+#define DIVIDE_UP(what,by) (((what)+(by)-1)/(by))
+#define ROUND_UP(what,by) (DIVIDE_UP((what),(by))*(by))
+
+#define ALLOC_KB DIVIDE_UP((ALLOC_END-START)+STACKSIZE_TOP,0x400)
+#define SECTORS_LEN ((SECTORS_END-START)/0x200)
+
+
+#define NIBBLE_TO_HEX1(nibble) ('0'+(nibble)+('A'-('9'+1))*((nibble&8)&&((nibble&2)||(nibble&4))))
+#define NIBBLE_TO_HEX(nibble) NIBBLE_TO_HEX1((nibble)&0xF)
+#define BYTE_TO_HEX(byte) NIBBLE_TO_HEX((byte)>>4),NIBBLE_TO_HEX((byte))
+
+/* Extract from <linux/serial_reg.h>: */
+#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */
+#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */
+#define UART_IER 1 /* Out: Interrupt Enable Register (DLAB=0) */
+#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */
+#define UART_LCR 3 /* Out: Line Control Register */
+#define UART_MCR 4 /* Out: Modem Control Register */
+#define UART_LSR 5 /* In: Line Status Register */
+#define UART_MSR 6 /* In: Modem Status Register */
+
+#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
+#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
+
+#define UART_MCR_RTS 0x02 /* RTS complement */
+#define UART_MCR_DTR 0x01 /* DTR complement */
+
+#define UART_MSR_DSR 0x20 /* Data Set Ready */
+
+#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+
+
+/* Macros: */
+
+ .macro outchar char
+ movw $0x0E00 | \char,%ax
+ movw $7,%bx
+ int $0x10
+ .endm
+
+ .macro stosw_sniff
+#ifdef DISABLE_SNIFF
+ nop
+#else
+ stosw
+#endif
+ .endm
+
+#ifdef DISABLE_ORG
+#define MYORG(offset)
+#else
+#define MYORG(offset) .org (offset) + START /* "+ START" MUST be on the end of line - WHY?!? */
+#endif
+
+ .macro pushALL
+ pushw %ax
+ pushw %bx
+ pushw %cx
+ pushw %dx
+ pushw %si
+ pushw %di
+ pushw %bp
+ .endm
+
+ .macro popALL
+ popw %bp
+ popw %di
+ popw %si
+ popw %dx
+ popw %cx
+ popw %bx
+ popw %ax
+ .endm
+
+#define PUSHALL_SIZE (7*2)
+#define PUSHALL_SI ((1/*%bp*/+1/*%di*/)*2)
+
+ .macro CallJumpVector0x13
+ pushf /* create 'lret' stack by this pushf... */
+ pushw %cs /* ...this segment... */
+ call JumpVector0x13 /* ...and this return address */
+ .endm
+
+
+
+/* Code starts here */
+/********************/
+
+#ifdef HAVE_GAS_ARCH_I8086
+ .arch i8086,nojumps
+#endif
+ .code16
+ .text
+ .globl _start
+_start:
+
+/* init stack */
+START:
+ cli /* just a paranoia, shouldn't be needed */
+ jmp InitRawStack /* We don't want to have 0x90 on offset 2 (one of recognization rules by DOS) */
+ .org START+0x03
+
+ .macro places offset length string
+ .org (\offset) + START
+ .ascii "\string"
+ .org (\offset) + (\length) + START /* we can't check whether it isn't too short :-( */
+ .endm
+ .macro placex offset length bytes
+ .org (\offset) + START
+ .byte \bytes
+ .org (\offset) + (\length) + START /* we can't check whether it isn't too short :-( */
+ .endm
+
+/* We rather supply empty (=zeroed) FAT filesystem table
+ */
+ places 0x03,8,"I13Sniff" /* OEM ID */
+ placex 0x43,4,"0x5E,0x81,0xA2,0x99" /* Volume Serial Number: 5E81A299 as "SERIAL99" */
+ places 0x47,11,"Int13Sniff\0" /* Volume Label */
+ places 0x52,8,"BootOnly" /* Filesystem ID */
+
+InitRawStack:
+ .org 0x5A + START
+
+ xorw %ax,%ax
+ movw %ax,%ss
+ movw $0x7C00,%sp
+ sti
+ outchar '1'
+ ljmp $0x7C0/*segment*/ , $InitContinue7C0-START/*offset*/
+
+InitContinue7C0:
+ outchar '3'
+
+/* move to top memory */
+ xorw %dx,%dx /* DX=null */
+ movw %dx,%ds
+ movw %ds:MEM_KBYTES,%ax
+ subw $ALLOC_KB,%ax
+ movw %ax,%ds:MEM_KBYTES
+ movb $6,%cl
+ shlw %cl,%ax
+ movw %ax,%es
+ xorw %bx,%bx /* buffer=ES:BX= topram:0x0000 */
+ movw $0x0200 | SECTORS_LEN,%ax /* READ16 (SECTORS_LEN) sectors */
+ xorw %dx,%dx /* Head 0, Drive 0x00 */
+ call ReadSectors
+ xorw %di,%di
+ pushw %cs
+ popw %ds
+ xorw %si,%si
+ movw $0x200/2,%cx
+repe cmpsw
+ pushw %es
+ movw $InitContinueTop-START,%ax
+ pushw %ax
+ movw $BadCmpMsg-START,%si
+ jnz PrintFatal
+ cmpw $SECTOR2_MAGIC,%es:(Sector2_MagicBuf-START)
+ je LReturn1
+/* fallthru */
+PrintFatal:
+ call PrintString
+PrintFatal_dead:
+ jmp PrintFatal_dead
+LReturn1:
+ lret
+
+Return1:
+ ret
+
+/* Interface to retry-capable INT13, set everything except CX */
+/* function may destroy DS value! */
+ReadSectors:
+ movw $0x0001,%cx /* Cylinder 0, Sector 1 */
+ int $0x13
+ jnc Return1
+ pushw %dx /* save drive for resetting the controller */
+ pushw %ax /* error code in AH */
+ movw $InitMsg-START,%si
+ call PrintString
+ pushw %bx /* offset... */
+ pushw %es /* and segment of bufffer */
+ pushw %ax /* count */
+ pushw %dx /* head */
+ pushw %cx /* CX<sec/cyl> */
+ pushw %dx /* drive */
+ movw $SF13_02_Msg-START,%si
+ call PrintString
+ movw $SnifferErrTail_MSG-START,%si
+ call PrintString_noPref
+ movb $0x00,%ah /* reset controller - FDC or HDC */
+ popw %dx /* restore the drive */
+ int $0x13
+ jmp ReadSectors
+
+PrintTrailNL:
+ movw $TrailNL_Msg-START,%si
+ jmp PrintString_noPref
+
+/* String is given in SI, returns updated SI */
+PrintString:
+ movb $'%',%al
+ call PrintChar
+PrintString_noPref:
+ pushw %cs
+ popw %ds
+PrintString_loop:
+ cld
+ lodsb
+ testb %al,%al
+ jz Return1
+ movw $PrintString_loop-START,%bx /* from now do just 'ret' to close the loop */
+ pushw %bx
+ testb $0x80,%al /* should be (x&E0==E0) */
+ jz PrintChar
+ testb $0x10,%al
+ jz PrintString_no0x
+ pushw %ax
+ movb $'$',%al
+ call PrintChar
+ popw %ax
+PrintString_no0x:
+ popw %bx /* discard $PrintString_loop-START */
+ popw %bx /* return address */
+ popw %dx /* value to print */
+ pushw %bx /* return back the return address */
+ movw $PrintString_loop-START,%bx
+ pushw %bx
+ testb $0x02,%al
+ jz PrintString_noHhex
+ pushw %ax
+ pushw %dx
+ call PrintString_Lhex
+ popw %dx
+ popw %ax
+PrintString_noHhex:
+ movb %dl,%dh
+ testb $0x01,%al
+Return1_jump1:
+ jz Return1
+
+/* One byte to print is in DH */
+PrintString_Lhex:
+ pushw %dx
+ movb $4,%cl
+ rorb %cl,%dh
+ call PrintString_Nhex
+ popw %dx
+
+/* One nibble to print is in the lower one of DH */
+PrintString_Nhex:
+ andb $0x0F,%dh
+ addb $'0',%dh
+ cmpb $'9'+1,%dh
+ jc PrintString_charDH
+ addb $'A'-('9'+1),%dh
+PrintString_charDH:
+ movb %dh,%al
+/* fallthru */
+
+/* Character is given in AL
+ * Preserves: DS, ES, SI, DI
+ * Destroys: AX (even AL!), BX, CX, DX
+ * DS is sometimes left preserved, sometimes set to DS=CS
+ */
+PrintChar:
+#ifdef SCREEN_PRINT
+ movb $0x0E,%ah /* print character */
+ movw $7,%bx
+ pushw %ax
+ int $0x10
+ popw %ax
+#else
+ xorb %bh,%bh /* assumed below */
+#endif
+#if defined(SERIAL_BAUDRATE) || defined(OUTPUT_STORE_DISK)
+ pushw %cs
+ popw %ds /* set DS=CS */
+ cmpb %bh,%ds:(SerialEnable-START)
+ jz Return1_jump1
+#ifdef SERIAL_BAUDRATE
+ jmp SerialPrintChar
+#else /* SERIAL_BAUDRATE */
+ jmp OutputStorePrintChar
+#endif /* SERIAL_BAUDRATE */
+#else /* defined(SERIAL_BAUDRATE) || defined(OUTPUT_STORE_DISK) */
+ ret
+#endif /* defined(SERIAL_BAUDRATE) || defined(OUTPUT_STORE_DISK) */
+
+
+#if defined(SERIAL_BAUDRATE) || defined(OUTPUT_STORE_DISK)
+SerialEnable:
+ .byte 0 /* map of port bits which want to be enabled */
+
+#ifdef OUTPUT_STORE_DISK
+#define OUTPUT_STORE_SerialEnable (0x02) /* FloppyPrintChar enabled */
+#else
+#define OUTPUT_STORE_SerialEnable (0x00)
+#endif
+
+#endif
+
+InitMsg:
+ .asciz "INIT: "
+BadCmpMsg:
+ .asciz "Disk 0x00 sector 0 doesn't match myself!"
+SF13_02_Msg:
+ .ascii "Read"
+Common16disk_Msg:
+ .asciz "16(drv=\xF1,CX<sec/cyl>=\xF3,head=\xF2,count=\xF1,buf=\xF3:\xF3)"
+SnifferErrTail_MSG:
+ .ascii "=\xF2 !"
+TrailNL_Msg:
+ .byte 13,10,0
+
+/*******************************************************************/
+/* Storage area - code isn't needed to be primary-sector reachable */
+/*******************************************************************/
+
+/**************************************************************/
+/* Final primary-sector signature */
+/**************************************************************/
+
+ MYORG(0x1FC)
+ .byte 0xDE,0xAD /* FAT32 defines somehow extended, 32-bit signature (=> 0xDEAD) */
+ .byte 0x55,0xAA
+
+/**************************************************************/
+/* Section run during boot but from the upper half of code */
+/**************************************************************/
+
+
+/* Main initialization */
+/***********************/
+/* DS invalid, ES==CS */
+InitContinueTop:
+ outchar ':'
+
+ pushw %cs
+ cli
+ popw %ss
+ movw $ALLOC_KB*1024,%sp
+ sti
+
+#ifdef OUTPUT_STORE_DISK
+ movw $OutputStoreBufSpaceStart-START,%di
+ movw $((OutputStoreBuf+0x200-OutputStoreBufSpaceStart)+1)/2,%cx /* NOTE_1: Buffer may got +1 overfilled */
+ xorw %ax,%ax
+ rep stosw
+#endif
+
+#ifndef SERIAL_BAUDRATE
+#ifdef OUTPUT_STORE_DISK
+ movb $OUTPUT_STORE_SerialEnable,%cs:(SerialEnable-START)
+#endif
+ movw $HelloMsg-START,%si
+ call PrintString
+#else /* SERIAL_BAUDRATE */
+ movb $0x55|OUTPUT_STORE_SerialEnable,%es:(SerialEnable-START)
+ movw $HelloMsg-START,%si
+ call PrintString /* this string will not have EOL when SERIAL_BAUDRATE is defined */
+ movb %ds:(SerialEnable-START),%cl
+ movw $PORTADDR_BASE,%si
+SerialHello_loop:
+ xorw %ax,%ax
+ movw %ax,%ds
+ lodsw
+ rorb $1,%cl
+ jnc SerialHello_skipOne
+ testw %ax,%ax
+ jz SerialHello_skipOne
+ pushw %cx /* push SerialEnable mask, S=1 */
+ pushw %si /* push PORTADDR_BASE+x pointer, S=2 */
+ pushw %ax /* print port base */
+ movw $SerialHelloPort_Msg-START,%si
+ call PrintString_noPref
+ popw %si /* restore PORTADDR_BASE+x pointer, S=1 */
+ popw %cx /* restore SerialEnable mask, S=0 */
+SerialHello_skipOne:
+ rorb $1,%cl /* skip unused even bits of SerialEnable mask */
+ cmpw $PORTADDR_BASE+4*2,%si
+ jne SerialHello_loop
+ call PrintTrailNL
+#endif
+
+/* now install our SniffFunction0x13 sniffer */
+
+ xorw %ax,%ax
+ movw %ax,%ds
+ movw $0x13*4,%si
+ pushw %cs
+ popw %es
+ movw $OrigVector0x13-START,%di
+ pushw %si
+ movw $SniffFunction0x13-START,%ax
+ cld
+ cli
+ movsw
+ movsw
+ popw %di /* = $0x13*4 */
+ pushw %ds
+ popw %es /* = null */
+ stosw_sniff /* $SniffFunction0x13-START */
+ pushw %cs
+ popw %ax
+ stosw_sniff
+ movw $0x18*4,%di /* ROM basic - failed boot */
+ movw $SniffFunction0x18-START,%ax
+ stosw_sniff
+ pushw %cs
+ popw %ax
+ stosw_sniff
+ sti
+#ifdef OUTPUT_STORE_DISK
+ incb %cs:(OutputStoreFlushEnable-START) /* we have now functional JumpVector0x13 */
+#endif
+ /* we WANT DS left with 0x0000 */
+ /* we WANT ES left with 0x0000 */
+
+/* and give the system control to disk=0x80/masterboot */
+ movw $0x0201,%ax /* READ16 1 sector */
+ movw $0x7C00,%bx /* buffer=ES:BX= 0x0000:0x7C00 */
+ pushw %ds
+ pushw %bx /* BX/DS on stack for later 'lret', S=2, prepared for far ret */
+ movw $0x0080,%dx /* Head 0, Drive 0x80 */
+ call ReadSectors /* it returns only when successfully read */
+ cmpw $0xAA55,%es:(0x7C00+0x1FE) /* 0x55,0xAA */
+ movw $BadSignatureMsg-START,%si
+ jne PrintFatal_jump1
+ cli /* IMPORTANT: Boot sectors must be run with CLI! */
+ lret /* lret to 0x0000:0x7C00 */
+
+SniffFunction0x18:
+ movw $Interrupt0x18Msg-START,%si /* %ds gets fixed in PrintFatal */
+PrintFatal_jump1:
+ jmp PrintFatal
+
+
+/* SerialPort handling code */
+/****************************/
+
+#ifdef SERIAL_BAUDRATE
+
+SerialPrintChar:
+
+/* Function assumes DS == CS, it preserves SI, DI, ES but uses ES==0 ! */
+/* Function expects character to print in AL, preserves it. */
+
+/* fallthru */
+SerialLoop:
+ movb $0,%ah /* offset from PORTADDR_BASE for port #1 */
+ xorw %bx,%bx /* any register */
+ pushw %es /* push ES, S=1 */
+ movw %bx,%es
+
+SerialLoop_loop:
+ movw $PORTADDR_BASE,%bx
+ addb %ah,%bl
+ movw %es:(%bx),%bx
+ testw %bx,%bx
+ jz SerialLoop_noport /* now we have port base in BX */
+ movb $1,%ch
+ movb %ah,%cl
+ rolb %cl,%ch
+ testb %ch,%ds:(SerialEnable-START)
+ jz SerialLoop_noport /* disabled port */
+ pushw %ax /* push CHARACTER and AH(port offset), S=2 */
+ cmpb $'%',%al
+ jnz SerialLoop_noInit
+
+/* Serial Init */
+ leaw UART_IER(%bx),%dx /* DX=+1, UAT_IER - interrupt enable */
+ xorb %al,%al /* NO interrupts */
+ outb %al,%dx
+ incw %dx
+ incw %dx /* DX=+3, UART_LCR - used as divisor enable */
+ movb $SERIAL_LCR_INIT | UART_LCR_DLAB,%al
+ outb %al,%dx
+ movw %bx,%dx /* DX=+0, UART_DLL - divisor LOW */
+ movb $(SERIAL_DIVISOR & 0xFF),%al
+ outb %al,%dx
+ incw %dx /* DX=+1, UART_DLM - divisor HIGH */
+ movb $(SERIAL_DIVISOR >> 8),%al
+ outb %al,%dx
+ incw %dx
+ incw %dx /* DX=+3, UART_LCR - line control */
+ movb $SERIAL_LCR_INIT,%al
+ outb %al,%dx
+ incw %dx /* DX=+4, UART_MCR - modem control */
+ movb $SERIAL_MCR_INIT,%al
+ outb %al,%dx
+ incw %dx /* DX=+5, UART_LSR - line status */
+ inb %dx,%al
+ incb %al
+ jz PrintChar_serial_invalidPort /* LSR port is 0xFF - no device on the bus */
+
+#ifdef SERIAL_REQUIRE_DSR
+ incw %dx /* DX=+6, UART_MSR - modem status */
+ xorw %cx,%cx /* Try ~ 60msec for DSR transition delayd by pure wiring after our DTR */
+PrintChar_serialWaitDSR:
+ inb %dx,%al
+ andb $UART_MSR_DSR,%al /* we MUST have AL==0 when passing to invalidPort ! */
+ jnz PrintChar_serialSend
+ loop PrintChar_serialWaitDSR
+ jmp PrintChar_serial_invalidPort
+#endif /* SERIAL_REQUIRE_DSR */
+
+SerialLoop_loop_jump1:
+ jmp SerialLoop_loop
+
+SerialLoop_noInit: /* still CHARACTER and AH(port offset) on stack, S=2 */
+PrintChar_serialSend:
+ movb $SERIAL_SENDWAIT,%ah
+PrintChar_serialSend_wait:
+ leaw UART_LSR(%bx),%dx /* UART_LSR - line status */
+ inb %dx,%al
+ andb $UART_LSR_THRE,%al /* test transmitter-buffer-empty bit */
+ jnz PrintChar_serialSend_free /* we MUST have AL==0 when passing to invalidPort ! */
+ loop PrintChar_serialSend_wait
+ decb %ah /* out-loop count SERIAL_SENDWAIT */
+ jnz PrintChar_serialSend_wait
+PrintChar_serial_invalidPort:
+ leaw UART_MCR(%bx),%dx /* UART_LSR - line status */
+ outb %al,%dx /* assumed AL==0: turn off DTR & RTS of the failing port */
+ movb %ds:(SerialEnable-START),%ah
+ pushw %ax /* pushed AH(SerialEnable), S=3 */
+ movb %al,%ds:(SerialEnable-START) /* assumed AL==0; disable temporarily complete serial output */
+ pushw %si /* save SI, S=4 */
+ pushw %bx /* port base to print out */
+ movw $SerialPortError_Msg-START,%si
+ call PrintString
+ popw %si /* recover SI, S=3 */
+ popw %bx /* restored BH=AH(SerialEnable), S=2 */
+ popw %ax /* restored CHARACTER and AH(port offset), S=1 */
+ movb %ah,%cl
+ movb $0xFE /* ==~1 */,%ch
+ rolb %cl,%ch /* masking-out pattern */
+ andb %ch,%bh /* mask-out the original SerialEnable left in BH */
+ movb %bh,%ds:(SerialEnable-START) /* disable the failed port for futher serial dumping */
+ jmp SerialLoop_noport
+
+PrintChar_serialSend_free:
+ movw %bx,%dx /* UART_TX - xmit buffer */
+ popw %ax /* restored CHARACTER and AH(port offset), S=1 */
+ outb %al,%dx /* final character transmit */
+
+SerialLoop_noport:
+ inc %ah
+ inc %ah /* skip by two bytes of PORTADDR_BASE entry offset */
+ cmp $4*2,%ah
+ jne SerialLoop_loop_jump1
+ popw %es /* pop ES, S=0 */
+#ifndef OUTPUT_STORE_DISK
+ ret
+#else
+/* FALLTHRU */
+#endif
+#endif /* SERIAL_BAUDRATE */
+
+/* OutputStore handling code */
+/*****************************/
+
+#ifdef OUTPUT_STORE_DISK
+
+#if OUTPUT_STORE_DISK!=0x00
+#error "int13sniff WILL destroy the data on OUTPUT_STORE_DISK!!! Are you sure?"
+#endif
+
+OutputStorePrintChar:
+
+/* Function assumes DS == CS, it preserves SI, DI, ES. */
+/* Function expects character to print in AL. */
+
+ testb $OUTPUT_STORE_SerialEnable,%ds:(SerialEnable-START)
+ jz Return3
+OS_NotDisabled:
+ cmp $13,%al /* we completely ignore and filter-out all '\r' */
+ je Return3
+ pushw %es /* SAVE %ES */
+ pushw %di /* SAVE %DI */
+ pushw %si /* SAVE %SI */
+ movw %ds:(OutputStoreBufPtr-START),%di
+ pushw %cs
+ popw %es /* ES=CS */
+ stosb
+OutputStoreTerminate: /* we will terminate the OutputStoreBuf at the given %DI position */
+ movw %di,%ds:(OutputStoreBufPtr-START)
+ movb $OUTPUT_STORE_EOF,%ds:(%di)
+ cmpb $0,%ds:(OutputStoreFlushEnable-START)
+ jz Return2pop_jump1 /* we cannot yet call CallJumpVector0x13 */
+ cmpb $10,%al
+ je OutputStoreFlush /* always flush bufer on message newline */
+ cmpw $(OutputStoreBuf-START)+0x200,%di
+ jnc OutputStoreFlush
+Return2pop_jump1:
+ jmp Return2pop
+
+Return3:
+ ret
+
+OutputStoreFlush:
+ movw $OUTPUT_STORE_WRITE_RETRIES,%bp
+OS_RetryWrite:
+ mov $0x08,%ah /* %AH=get drive geometry, WARNING: DESTROYS %DI! */
+ mov $OUTPUT_STORE_DISK,%dl
+ CallJumpVector0x13 /* now %DH=maximum heads, %CX=maximum cylinder§or */
+ jc OS_MediaOver
+ movw %cx,%bx
+ xchg %bh,%bl
+ rol $1,%bh
+ rol $1,%bh
+ andb $0x03,%bh /* now %BX==# of cylinders */
+ andb $0x3F,%cl /* now %CL==# of sectors */
+ pushw %cx /* SAVE LOW==# of sectors */
+ inc %dh /* now %DH==# of heads */
+ movb %dh,%al
+ mulb %cl /* now %AX==# of sectors in cylinder */
+ movw %ax,%cx
+ /* now we have %CX==# of sectors in cylinder, %BX=# of cylinders */
+ movw %cs:(OutputStoreAddress-START+0),%ax
+ movw %cs:(OutputStoreAddress-START+2),%dx /* %DX:%AX==OutputStoreAddress */
+ divw %cx /* now %AX==cylinder, %DX==head§or */
+ cmp %ax,%bx
+ popw %bx /* RESTORE ->%BL==# of sectors */
+ jc OS_MediaOver /* cylinders exceeded */
+ xchg %ax,%dx
+ divb %bl /* now %AL==head, %AH=0-based sector (and %DX==cylinder) */
+ incb %ah /* now %AL==head, %AH=1-based sector (and %DX==cylinder) */
+ testb $0xC0,%ah
+ jnz OS_MediaOver
+ testb $0xFC,%dh
+ jnz OS_MediaOver
+ movb %ah,%cl
+ movb %dl,%ch
+ rorb $1,%dh
+ rorb $1,%dh
+ orb %dh,%cl /* now %CX==cylinder§or in BIOS format */
+ movb %al,%dh /* now %DH==head */
+ pushw %cs
+ popw %ds /* DS=CS */
+ movb $OUTPUT_STORE_DISK,%dl
+ movw $0x0301,%ax /* %AH=write sectors, %AL=1 sector */
+ movw $(OutputStoreBuf-START),%bx
+ pushw %cs
+ popw %es /* ES=CS */
+ CallJumpVector0x13
+ jnc OS_WriteOK
+ movw %ax,%es /* %ES=Write16 error code */
+ xorb %ah,%ah /* %AH=reset drive */
+ CallJumpVector0x13
+ decw %bp
+ jnz OS_RetryWrite
+ andb $~OUTPUT_STORE_SerialEnable,%ds:(SerialEnable-START) /* OutputStorePrintChar got DISABLED here */
+ pushw %es /* Write16 error code, for secondary "SnifferErrTail_MSG" */
+ /* now parameters for "Common16disk_Msg": */
+ pushw %bx /* buf 2nd */
+ pushw %cs /* buf 1st (%ES has been destroyed by "Write16 error code" */
+ movb $0x01,%al /* "count" has been destroyed by "reset disk" call */
+ pushw %ax /* count */
+ pushw %dx /* head */
+ pushw %cx /* CX<sec/cyl> */
+ pushw %dx /* drive */
+
+OS_MediaOver:
+ movw $OutputFailedWrite_Msg-START,%si
+ call PrintString
+ movw $Common16disk_Msg-START,%si
+ call PrintString_noPref /* pops up 6*2 bytes (6 words) */
+ movw $SnifferErrTail_MSG-START,%si
+ call PrintString_noPref /* pops up 1*2 bytes (1 word ) */
+Return2pop:
+ popw %si /* RESTORE %SI */
+ popw %di /* RESTORE %DI */
+ popw %es /* RESTORE %ES */
+Return2: ret
+
+OS_WriteOK:
+ cmpw $(OutputStoreBuf-START)+0x200,%ds:(OutputStoreBufPtr-START)
+ jc Return2pop /* buffer is not yet filled */
+ incw %ds:(OutputStoreAddress-START+0)
+ jnz OS_IncAddrNotWordCarry
+ incw %ds:(OutputStoreAddress-START+2)
+OS_IncAddrNotWordCarry:
+ movw $OutputStoreBuf-START,%di
+ pushw %di
+ xorw %ax,%ax
+ movw $0x200/2,%cx
+ rep stosw /* OutputStore got cleared */
+ popw %di
+ movb $10,%al /* we want to immediately Flush even the new sector */
+ jmp OutputStoreTerminate
+
+#endif /* OUTPUT_STORE_DISK */
+
+/**************************************************************/
+/* Section for INT13 sniffing */
+/* THIS point may start to be after 0x200 boundary */
+/**************************************************************/
+
+SniffFunction0x13:
+ pushw %ax /* trash */
+ pushw %ds
+ pushALL
+
+ cmpb $0x00,%ah /* reset */
+ jne SF13_not00
+ movw $JumpVector0x13popa-START,%ax
+ pushw %ax /* return address */
+ pushw %dx /* drive */
+ movw $SF13_00_Msg-START,%si
+JumpVector0x13printStringPopa:
+ call PrintString
+ jmp PrintTrailNL
+
+SF13_not00:
+ cmpb $0x02,%ah /* read16 */
+ jne SF13_not02
+ pushw %bx /* buf 2nd */
+ pushw %es /* buf 1st */
+ pushw %ax /* count */
+ pushw %dx /* head */
+ pushw %cx /* CX<sec/cyl> */
+ pushw %dx /* drive */
+ movw $SF13_02_Msg-START,%si
+ call PrintString
+Sniffer13bottomStdHalf:
+ call CallVector0x13
+ movw $SnifferOKTail_Msg-START,%si
+ jnc SF13_not00_tail /* ...if CY is SET */
+Sniffer13DumpErrorAH:
+ movw $SnifferErrTail_MSG-START,%si
+ pushw %ax
+SF13_not00_tail:
+Sniffer13iretPrintStringFinal:
+ call PrintString_noPref
+ popALL
+ popw %ds
+ incw %sp
+ incw %sp /* trash discarded */
+ iret
+
+SF13_not02:
+ cmpb $0x41,%ah /* presence32 */
+ jne SF13_not41
+ cmpw $0x55AA,%bx
+ jne SF13_not41
+ pushw %dx /* drive */
+ movw $SF13_41_Msg-START,%si
+ call PrintString
+ call CallVector0x13
+ cmp $0xAA55,%bx
+ jne Sniffer13DumpErrorAH
+ pushw %cx /* supports */
+ pushw %ax /* version */
+ movw $SF13_41_out_Msg-START,%si
+ jmp Sniffer13iretPrintStringFinal
+
+CallVector0x13:
+ popw %ax /* return address */
+ pushw %bp
+ movw %sp,%bp
+ movw %ax,%ss:2/*%bp*/+PUSHALL_SIZE+2/*%ds*/(%bp) /* store %ax to 'trash' */
+ popw %bp
+ popALL
+ popw %ds
+ CallJumpVector0x13
+ pushw %ds
+ pushALL /* stack is back to normal NOW */
+ pushw %bp /* trash - just to prepare return address16 */
+ pushw %ax
+ pushw %bp
+ movw %sp,%bp
+ movw %ss:2/*%bp*/+2/*%ax*/+2/*return16*/+PUSHALL_SIZE+2/*%ds*/(%bp),%ax
+ movw %ax,%ss:2/*%bp*/+2/*ax*/(%bp)
+ pushf
+ pop %ax
+ movw %ax,%ss:2/*%bp*/+2/*%ax*/+2/*return16*/+PUSHALL_SIZE+2/*%ds*/+2/*trash*/+4/*ret-seg:offs*/(%bp)
+ popw %bp
+ popw %ax
+ ret /* to prepared return16 and now will be stack in normal again */
+
+SF13_not41:
+ cmpb $0x42,%ah /* read32 */
+ je SF13_do42
+ jmp JumpVector0x13popa /* too far for conditional-jump */
+
+SF13_do42:
+ movb %ds:2(%si),%al /* count */
+ pushw %ax
+ pushw %ds:8(%si) /* LBA32 sector LOWEST */
+ pushw %ds:8+2(%si) /* LBA32 sector LOWER */
+ pushw %ds:8+4(%si) /* LBA32 sector HIGHER */
+ pushw %ds:8+6(%si) /* LBA32 sector HIGHEST */
+ pushw %dx /* drive */
+ movw $SF13_42_Msg-START,%si
+ call PrintString /* first half of the entry-message */
+
+ movw %sp,%bp
+ movw %ss:PUSHALL_SI(%bp),%si
+ movw %ss:PUSHALL_SIZE(%bp),%ds /* restore DS:SI packet */
+
+ movw %ds:4(%si),%ax /* buf16 offset */
+ pushw %ax /* buf16 offset */
+ andw %ds:4+2(%si),%ax /* buf16 segment */
+ pushw %ds:4+2(%si) /* buf16 segment */
+ incw %ax
+ movw $SF13_42_buf16_Msg-START,%si
+ jnz SF13_42_buf16 /* buf16 was NOT 0xFFFF:0xFFFF => jump as OK */
+ addw $4,%sp /* drop buf16 address seg:offs */
+ pushw %ds:0x10(%si) /* 64-bit buffer LOWEST */
+ pushw %ds:0x10+2(%si) /* 64-bit buffer LOWER */
+ pushw %ds:0x10+4(%si) /* 64-bit buffer HIGHER */
+ pushw %ds:0x10+6(%si) /* 64-bit buffer HIGHEST */
+ movw $SF13_42_buf64_Msg-START,%si
+
+SF13_42_buf16: /* too far for conditional-jump */
+ call PrintString_noPref
+ jmp Sniffer13bottomStdHalf
+
+JumpVector0x13popa:
+ popALL
+ popw %ds
+ incw %sp
+ incw %sp /* trash discarded */
+JumpVector0x13:
+ .byte 0xEA /* ljmp */
+OrigVector0x13:
+ .skip 4
+
+/* Serial support upper half initialization messages */
+/*****************************************************/
+
+#ifdef SERIAL_BAUDRATE
+
+SerialPortError_Msg:
+ .asciz "SerialPort \xF3 error: stopping its communication\r\n"
+
+SerialHelloPort_Msg:
+ .asciz " \xF3"
+
+#endif /* SERIAL_BAUDRATE */
+
+
+/* Main upper half initialization messages */
+/*******************************************/
+
+HelloMsg:
+ .ascii "INT13-Sniff, version ",VERSION,", RCS revision ",REVISION
+#ifdef OUTPUT_STORE_DISK
+ .ascii ", Output Store on disk 0x"
+ .byte BYTE_TO_HEX(OUTPUT_STORE_DISK)
+#endif
+#ifdef SERIAL_BAUDRATE
+ .ascii ", using serial ports:"
+#else
+ .byte 13,10
+#endif
+ .byte 0
+BadSignatureMsg:
+ .asciz "Disk 0x80 has invalid signature!"
+
+
+/* Interrupt sniffing messages */
+/*******************************/
+
+Interrupt0x18Msg:
+ .asciz "Interrupt 0x18 - Failed boot!"
+SF13_00_Msg:
+ .asciz "Reset(drv=\xF1)"
+SF13_41_Msg:
+ .asciz "Presence32(drv=\xF1)"
+SF13_41_out_Msg:
+ .ascii "=(version=\xF2,supports=\xF3)"
+ /* fallthru */
+SnifferOKTail_Msg:
+ .ascii " OK"
+ .byte 13,10,0
+SF13_42_Msg:
+ .asciz "Read32(drv=\xF1,LBA32=\xF3\xE3\xE3\xE3,count=\xF1,buf="
+SF13_42_buf16_Msg:
+ .asciz "\xF3:\xF3)"
+SF13_42_buf64_Msg:
+ .asciz "\xF3\xE3\xE3\xE3)"
+
+
+/* Output Store messages / variables */
+/*************************************/
+#ifdef OUTPUT_STORE_DISK
+
+OutputFailedWrite_Msg:
+ .asciz "Output Store error, stopping store: Write"
+
+OutputStoreBufPtr:
+ .word OutputStoreBufSpaceStart-START
+OutputStoreAddress:
+#ifdef OUTPUT_STORE_ADDRESS
+ .long OUTPUT_STORE_ADDRESS
+#else
+ .long (OutputStoreBuf-START)/0x200
+#endif
+OutputStoreFlushEnable:
+ .byte 0 /* disable calling of JumpVector0x13 as it is not functional yet */
+
+#endif
+/**************************************************************/
+/* Sectors finalisation */
+/**************************************************************/
+
+#ifndef OUTPUT_STORE_DISK
+ALLOC_END:
+#endif
+
+ MYORG(ROUND_UP(.+2-START,0x200)-2)
+Sector2_MagicBuf:
+ .word SECTOR2_MAGIC
+
+#ifdef OUTPUT_STORE_DISK
+OutputStoreBuf:
+#endif
+ .ascii "\n<OuTpUt_sToRe>\n"
+#ifdef OUTPUT_STORE_DISK
+OutputStoreBufSpaceStart:
+ .ascii "Buffer empty, no data stored yet.\n"
+#else
+ .ascii "OUTPUT_STORE_DISK not defined, Output Store disabled!\n"
+#endif
+ .byte OUTPUT_STORE_EOF
+
+ MYORG(ROUND_UP(.-START,0x200)) /* WARNING, we may overfull the buffer by +1 bytes, see NOTE_1 */
+
+#ifdef OUTPUT_STORE_DISK
+ .equ ALLOC_END,.+1 /* we need one 'trash' byte for exceeding OUTPUT_STORE_EOF */
+#endif
+
+SECTORS_END:
+
+/* vi:ts=8:sw=8
+ */