/* * misc/int13sniff.S * * Copyright (C) 2000 * Partition Surprise Team * * $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 : */ #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 */ 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=\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 */ 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 */ 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\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 */