openpgp: 7E25094870599135A83DD2C6C446E92ECE0D66B2
[www.jankratochvil.net.git] / project / int13sniff / int13sniff.S
1 /*
2  *      misc/int13sniff.S
3  *
4  *      Copyright (C) 2000
5  *      Partition Surprise Team <surprise-dev@lists.sourceforge.net>
6  *
7  *      $Id: int13sniff.S,v 1.4 2001/02/13 00:47:18 kratochvil Exp $
8  */
9
10
11 /*
12  *
13  *      Sniffer for INT13 calls
14  *
15  *      Prepare your floppy and reboot from it with 0x80 disk for boot-sniffing:
16  *      ANY DATA ON YOUR FLOPPY (/dev/fd0) WILL BE ERASED BY THIS COMMAND!
17  *
18  *              make int13sniff.fd0
19  *
20  *
21  */
22
23
24 /* !!!  All defines below must be COMMENTED-OUT !
25  * !!!  Define to value 0 has no effect.
26  */
27
28 /* Enable of normal screen dump output.
29  * You can probably never need to undefine it, only if it severly
30  * harms some needed (fullscreen) application display output.
31  */
32 #define SCREEN_PRINT 1
33
34 /* Enable (if defined) dump output to all serials found
35  */
36 #define SERIAL_BAUDRATE 9600
37
38 /* Enable to refuse dumping output to port without DSR active
39  *  - pro: doesn't get slow by dumping to not-connected ports
40  *  - con: some cables may not have DSR (DTR<->DSR wiring would be sufficient)
41  */
42 #define SERIAL_REQUIRE_DSR
43
44 /* Enable to dump all messages back to floppy
45  *  - con: message output is slowed down a bit
46  * WARNING: some BIOSes fail to report geometry (INT 0x13/AH=0x08) for HDD!
47  */
48 #define OUTPUT_STORE_DISK 0x00
49
50 /* Linear sector offset where to start writing buffer sectors
51  * If undefined, it is calculated to be the last sector of "int13sniff.bin".
52 #define OUTPUT_STORE_ADDRESS -1
53  */
54
55 /* Stack size to reserve in the top-memory area
56  * WARNING: Due to SECTORS_LEN reading, this value MUST be always >=
57  *          than the sector size (0x200)!
58  */
59 #define STACKSIZE_TOP 0x200
60
61 /* Maintainers: Disable occupying of any (0x13 & 0x18) interrupt vectors
62 #define DISABLE_SNIFF 1
63  */
64
65 /* Maintainers: Disable .org macroinstructions: ONLY FOR compilation tuning!
66  *  - image produced doen't have any functionality!
67 #define DISABLE_ORG 1
68  */
69
70
71 /* Internal defines */
72 #define SERIAL_SENDWAIT 16                              /* multiplied by 0x10000, Linux kernel has ~15 (looping 1E6 times) */
73 #define SERIAL_LCR_INIT (UART_LCR_WLEN8)                /* 8N1, no DLAB */
74 #define SERIAL_MCR_INIT (UART_MCR_DTR | UART_MCR_RTS)   /* we are RTSed! */
75 #define MEM_KBYTES    0x413     /* BIOS variable */
76 #define PORTADDR_BASE 0x400      /* BIOS variable */
77 #define SECTOR2_MAGIC 0xEFBE
78 #define SERIAL_DIVISOR (115200/SERIAL_BAUDRATE)
79 #define OUTPUT_STORE_WRITE_RETRIES 5            /* how many times to try Write16 & ResetDisk sequence */
80 #define OUTPUT_STORE_EOF 26
81
82 #define DIVIDE_UP(what,by) (((what)+(by)-1)/(by))
83 #define ROUND_UP(what,by) (DIVIDE_UP((what),(by))*(by))
84
85 #define ALLOC_KB DIVIDE_UP((ALLOC_END-START)+STACKSIZE_TOP,0x400)
86 #define SECTORS_LEN ((SECTORS_END-START)/0x200)
87
88
89 #define NIBBLE_TO_HEX1(nibble) ('0'+(nibble)+('A'-('9'+1))*((nibble&8)&&((nibble&2)||(nibble&4))))
90 #define NIBBLE_TO_HEX(nibble) NIBBLE_TO_HEX1((nibble)&0xF)
91 #define BYTE_TO_HEX(byte) NIBBLE_TO_HEX((byte)>>4),NIBBLE_TO_HEX((byte))
92
93 /* Extract from <linux/serial_reg.h>: */
94 #define UART_TX         0       /* Out: Transmit buffer           (DLAB=0) */
95 #define UART_DLL        0       /* Out: Divisor Latch Low         (DLAB=1) */
96 #define UART_IER        1       /* Out: Interrupt Enable Register (DLAB=0) */
97 #define UART_DLM        1       /* Out: Divisor Latch High        (DLAB=1) */
98 #define UART_LCR        3       /* Out: Line Control Register */
99 #define UART_MCR        4       /* Out: Modem Control Register */
100 #define UART_LSR        5       /* In:  Line Status Register */
101 #define UART_MSR        6       /* In:  Modem Status Register */
102
103 #define UART_LCR_DLAB   0x80    /* Divisor latch access bit */
104 #define UART_LCR_WLEN8  0x03    /* Wordlength: 8 bits */
105
106 #define UART_MCR_RTS    0x02    /* RTS complement */
107 #define UART_MCR_DTR    0x01    /* DTR complement */
108
109 #define UART_MSR_DSR    0x20    /* Data Set Ready */
110
111 #define UART_LSR_THRE   0x20    /* Transmit-hold-register empty */
112
113
114 /* Macros: */
115
116         .macro  outchar char
117         movw    $0x0E00 | \char,%ax
118         movw    $7,%bx
119         int     $0x10
120         .endm
121
122         .macro  stosw_sniff
123 #ifdef DISABLE_SNIFF
124         nop
125 #else
126         stosw
127 #endif
128         .endm
129
130 #ifdef DISABLE_ORG
131 #define MYORG(offset)
132 #else
133 #define MYORG(offset) .org (offset) + START             /* "+ START" MUST be on the end of line - WHY?!? */
134 #endif
135
136         .macro  pushALL
137         pushw   %ax
138         pushw   %bx
139         pushw   %cx
140         pushw   %dx
141         pushw   %si
142         pushw   %di
143         pushw   %bp
144         .endm
145
146         .macro  popALL
147         popw    %bp
148         popw    %di
149         popw    %si
150         popw    %dx
151         popw    %cx
152         popw    %bx
153         popw    %ax
154         .endm
155
156 #define PUSHALL_SIZE (7*2)
157 #define PUSHALL_SI   ((1/*%bp*/+1/*%di*/)*2)
158
159         .macro  CallJumpVector0x13
160         pushf                   /* create 'lret' stack by this pushf... */
161         pushw   %cs             /* ...this segment... */
162         call    JumpVector0x13  /* ...and this return address */
163         .endm
164
165
166
167 /* Code starts here */
168 /********************/
169
170 #ifdef HAVE_GAS_ARCH_I8086
171         .arch   i8086,nojumps
172 #endif
173         .code16
174         .text
175         .globl  _start
176 _start:
177
178 /* init stack */
179 START:
180         cli                     /* just a paranoia, shouldn't be needed */
181         jmp     InitRawStack    /* We don't want to have 0x90 on offset 2 (one of recognization rules by DOS) */
182         .org    START+0x03
183
184         .macro  places offset length string
185         .org    (\offset) + START
186         .ascii  "\string"
187         .org    (\offset) + (\length) + START           /* we can't check whether it isn't too short :-(  */
188         .endm
189         .macro  placex offset length bytes
190         .org    (\offset) + START
191         .byte   \bytes
192         .org    (\offset) + (\length) + START           /* we can't check whether it isn't too short :-(  */
193         .endm
194
195 /* We rather supply empty (=zeroed) FAT filesystem table
196  */
197         places  0x03,8,"I13Sniff"               /* OEM ID */
198         placex  0x43,4,"0x5E,0x81,0xA2,0x99"    /* Volume Serial Number: 5E81A299 as "SERIAL99" */
199         places  0x47,11,"Int13Sniff\0"          /* Volume Label */
200         places  0x52,8,"BootOnly"               /* Filesystem ID */
201
202 InitRawStack:
203         .org    0x5A + START
204
205         xorw    %ax,%ax
206         movw    %ax,%ss
207         movw    $0x7C00,%sp
208         sti
209         outchar '1'
210         ljmp    $0x7C0/*segment*/ , $InitContinue7C0-START/*offset*/
211
212 InitContinue7C0:
213         outchar '3'
214
215 /* move to top memory */
216         xorw    %dx,%dx         /* DX=null */
217         movw    %dx,%ds
218         movw    %ds:MEM_KBYTES,%ax
219         subw    $ALLOC_KB,%ax
220         movw    %ax,%ds:MEM_KBYTES
221         movb    $6,%cl
222         shlw    %cl,%ax
223         movw    %ax,%es
224         xorw    %bx,%bx         /* buffer=ES:BX= topram:0x0000 */
225         movw    $0x0200 | SECTORS_LEN,%ax       /* READ16 (SECTORS_LEN) sectors */
226         xorw    %dx,%dx         /* Head 0, Drive 0x00 */
227         call    ReadSectors
228         xorw    %di,%di
229         pushw   %cs
230         popw    %ds
231         xorw    %si,%si
232         movw    $0x200/2,%cx
233 repe    cmpsw
234         pushw   %es
235         movw    $InitContinueTop-START,%ax
236         pushw   %ax
237         movw    $BadCmpMsg-START,%si
238         jnz     PrintFatal
239         cmpw    $SECTOR2_MAGIC,%es:(Sector2_MagicBuf-START)
240         je      LReturn1
241 /* fallthru */
242 PrintFatal:
243         call    PrintString
244 PrintFatal_dead:
245         jmp     PrintFatal_dead
246 LReturn1:
247         lret
248
249 Return1:
250         ret
251
252 /* Interface to retry-capable INT13, set everything except CX */
253 /* function may destroy DS value! */
254 ReadSectors:
255         movw    $0x0001,%cx     /* Cylinder 0, Sector 1 */
256         int     $0x13
257         jnc     Return1
258         pushw   %dx     /* save drive for resetting the controller */
259         pushw   %ax     /* error code in AH */
260         movw    $InitMsg-START,%si
261         call    PrintString
262         pushw   %bx     /* offset... */
263         pushw   %es     /* and segment of bufffer */
264         pushw   %ax     /* count */
265         pushw   %dx     /* head */
266         pushw   %cx     /* CX<sec/cyl> */
267         pushw   %dx     /* drive */
268         movw    $SF13_02_Msg-START,%si
269         call    PrintString
270         movw    $SnifferErrTail_MSG-START,%si
271         call    PrintString_noPref
272         movb    $0x00,%ah       /* reset controller - FDC or HDC */
273         popw    %dx             /* restore the drive */
274         int     $0x13
275         jmp     ReadSectors
276
277 PrintTrailNL:
278         movw    $TrailNL_Msg-START,%si
279         jmp     PrintString_noPref
280
281 /* String is given in SI, returns updated SI */
282 PrintString:
283         movb    $'%',%al
284         call    PrintChar
285 PrintString_noPref:
286         pushw   %cs
287         popw    %ds
288 PrintString_loop:
289         cld
290         lodsb
291         testb   %al,%al
292         jz      Return1
293         movw    $PrintString_loop-START,%bx     /* from now do just 'ret' to close the loop */
294         pushw   %bx
295         testb   $0x80,%al       /* should be (x&E0==E0) */
296         jz      PrintChar
297         testb   $0x10,%al
298         jz      PrintString_no0x
299         pushw   %ax
300         movb    $'$',%al
301         call    PrintChar
302         popw    %ax
303 PrintString_no0x:
304         popw    %bx     /* discard $PrintString_loop-START */
305         popw    %bx     /* return address */
306         popw    %dx     /* value to print */
307         pushw   %bx     /* return back the return address */
308         movw    $PrintString_loop-START,%bx
309         pushw   %bx
310         testb   $0x02,%al
311         jz      PrintString_noHhex
312         pushw   %ax
313         pushw   %dx
314         call    PrintString_Lhex
315         popw    %dx
316         popw    %ax
317 PrintString_noHhex:
318         movb    %dl,%dh
319         testb   $0x01,%al
320 Return1_jump1:
321         jz      Return1
322
323 /* One byte to print is in DH */
324 PrintString_Lhex:
325         pushw   %dx
326         movb    $4,%cl
327         rorb    %cl,%dh
328         call    PrintString_Nhex
329         popw    %dx
330
331 /* One nibble to print is in the lower one of DH */
332 PrintString_Nhex:
333         andb    $0x0F,%dh
334         addb    $'0',%dh
335         cmpb    $'9'+1,%dh
336         jc      PrintString_charDH
337         addb    $'A'-('9'+1),%dh
338 PrintString_charDH:
339         movb    %dh,%al
340 /* fallthru */
341
342 /* Character is given in AL
343  * Preserves: DS, ES, SI, DI
344  * Destroys: AX (even AL!), BX, CX, DX
345  * DS is sometimes left preserved, sometimes set to DS=CS
346  */
347 PrintChar:
348 #ifdef SCREEN_PRINT
349         movb    $0x0E,%ah       /* print character */
350         movw    $7,%bx
351         pushw   %ax
352         int     $0x10
353         popw    %ax
354 #else
355         xorb    %bh,%bh         /* assumed below */
356 #endif
357 #if defined(SERIAL_BAUDRATE) || defined(OUTPUT_STORE_DISK)
358         pushw   %cs
359         popw    %ds             /* set DS=CS */
360         cmpb    %bh,%ds:(SerialEnable-START)
361         jz      Return1_jump1
362 #ifdef SERIAL_BAUDRATE
363         jmp     SerialPrintChar
364 #else /* SERIAL_BAUDRATE */
365         jmp     OutputStorePrintChar
366 #endif /* SERIAL_BAUDRATE */
367 #else /* defined(SERIAL_BAUDRATE) || defined(OUTPUT_STORE_DISK) */
368         ret
369 #endif /* defined(SERIAL_BAUDRATE) || defined(OUTPUT_STORE_DISK) */
370
371
372 #if defined(SERIAL_BAUDRATE) || defined(OUTPUT_STORE_DISK)
373 SerialEnable:
374         .byte   0       /* map of port bits which want to be enabled */
375
376 #ifdef OUTPUT_STORE_DISK
377 #define OUTPUT_STORE_SerialEnable (0x02)        /* FloppyPrintChar enabled */
378 #else
379 #define OUTPUT_STORE_SerialEnable (0x00)
380 #endif
381
382 #endif
383
384 InitMsg:
385         .asciz  "INIT: "
386 BadCmpMsg:
387         .asciz  "Disk 0x00 sector 0 doesn't match myself!"
388 SF13_02_Msg:
389         .ascii  "Read"
390 Common16disk_Msg:
391         .asciz  "16(drv=\xF1,CX<sec/cyl>=\xF3,head=\xF2,count=\xF1,buf=\xF3:\xF3)"
392 SnifferErrTail_MSG:
393         .ascii  "=\xF2 !"
394 TrailNL_Msg:
395         .byte   13,10,0
396
397 /*******************************************************************/
398 /* Storage area - code isn't needed to be primary-sector reachable */
399 /*******************************************************************/
400
401 /**************************************************************/
402 /* Final primary-sector signature                             */
403 /**************************************************************/
404
405         MYORG(0x1FC)
406         .byte   0xDE,0xAD       /* FAT32 defines somehow extended, 32-bit signature (=> 0xDEAD) */
407         .byte   0x55,0xAA
408
409 /**************************************************************/
410 /* Section run during boot but from the upper half of code    */
411 /**************************************************************/
412
413
414 /* Main initialization */
415 /***********************/
416 /* DS invalid, ES==CS */
417 InitContinueTop:
418         outchar ':'
419
420         pushw   %cs
421         cli
422         popw    %ss
423         movw    $ALLOC_KB*1024,%sp
424         sti
425
426 #ifdef OUTPUT_STORE_DISK
427         movw    $OutputStoreBufSpaceStart-START,%di
428         movw    $((OutputStoreBuf+0x200-OutputStoreBufSpaceStart)+1)/2,%cx      /* NOTE_1: Buffer may got +1 overfilled */
429         xorw    %ax,%ax
430         rep     stosw
431 #endif
432
433 #ifndef SERIAL_BAUDRATE
434 #ifdef OUTPUT_STORE_DISK
435         movb    $OUTPUT_STORE_SerialEnable,%cs:(SerialEnable-START)
436 #endif
437         movw    $HelloMsg-START,%si
438         call    PrintString
439 #else /* SERIAL_BAUDRATE */
440         movb    $0x55|OUTPUT_STORE_SerialEnable,%es:(SerialEnable-START)
441         movw    $HelloMsg-START,%si
442         call    PrintString             /* this string will not have EOL when SERIAL_BAUDRATE is defined */
443         movb    %ds:(SerialEnable-START),%cl
444         movw    $PORTADDR_BASE,%si
445 SerialHello_loop:
446         xorw    %ax,%ax
447         movw    %ax,%ds
448         lodsw
449         rorb    $1,%cl
450         jnc     SerialHello_skipOne
451         testw   %ax,%ax
452         jz      SerialHello_skipOne
453         pushw   %cx                             /* push SerialEnable mask, S=1 */
454         pushw   %si                             /* push PORTADDR_BASE+x pointer, S=2 */
455         pushw   %ax                             /* print port base */
456         movw    $SerialHelloPort_Msg-START,%si
457         call    PrintString_noPref
458         popw    %si                             /* restore PORTADDR_BASE+x pointer, S=1 */
459         popw    %cx                             /* restore SerialEnable mask, S=0 */
460 SerialHello_skipOne:
461         rorb    $1,%cl                          /* skip unused even bits of SerialEnable mask */
462         cmpw    $PORTADDR_BASE+4*2,%si
463         jne     SerialHello_loop
464         call    PrintTrailNL
465 #endif
466
467 /* now install our SniffFunction0x13 sniffer */
468
469         xorw    %ax,%ax
470         movw    %ax,%ds
471         movw    $0x13*4,%si
472         pushw   %cs
473         popw    %es
474         movw    $OrigVector0x13-START,%di
475         pushw   %si
476         movw    $SniffFunction0x13-START,%ax
477         cld
478         cli
479         movsw
480         movsw
481         popw    %di     /* = $0x13*4 */
482         pushw   %ds
483         popw    %es     /* = null */
484         stosw_sniff     /* $SniffFunction0x13-START */
485         pushw   %cs
486         popw    %ax
487         stosw_sniff
488         movw    $0x18*4,%di     /* ROM basic - failed boot */
489         movw    $SniffFunction0x18-START,%ax
490         stosw_sniff
491         pushw   %cs
492         popw    %ax
493         stosw_sniff
494         sti
495 #ifdef OUTPUT_STORE_DISK
496         incb    %cs:(OutputStoreFlushEnable-START)      /* we have now functional JumpVector0x13 */
497 #endif
498         /* we WANT DS left with 0x0000 */
499         /* we WANT ES left with 0x0000 */
500
501 /* and give the system control to disk=0x80/masterboot */
502         movw    $0x0201,%ax     /* READ16 1 sector */
503         movw    $0x7C00,%bx     /* buffer=ES:BX= 0x0000:0x7C00 */
504         pushw   %ds
505         pushw   %bx             /* BX/DS on stack for later 'lret', S=2, prepared for far ret */
506         movw    $0x0080,%dx     /* Head 0, Drive 0x80 */
507         call    ReadSectors             /* it returns only when successfully read */
508         cmpw    $0xAA55,%es:(0x7C00+0x1FE)              /* 0x55,0xAA */
509         movw    $BadSignatureMsg-START,%si
510         jne     PrintFatal_jump1
511         cli                     /* IMPORTANT: Boot sectors must be run with CLI! */
512         lret                    /* lret to 0x0000:0x7C00 */
513
514 SniffFunction0x18:
515         movw    $Interrupt0x18Msg-START,%si     /* %ds gets fixed in PrintFatal */
516 PrintFatal_jump1:
517         jmp     PrintFatal
518
519
520 /* SerialPort handling code */
521 /****************************/
522
523 #ifdef SERIAL_BAUDRATE
524
525 SerialPrintChar:
526
527 /* Function assumes DS == CS, it preserves SI, DI, ES but uses ES==0 ! */
528 /* Function expects character to print in AL, preserves it. */
529
530 /* fallthru */
531 SerialLoop:
532         movb    $0,%ah          /* offset from PORTADDR_BASE for port #1 */
533         xorw    %bx,%bx         /* any register */
534         pushw   %es             /* push ES, S=1 */
535         movw    %bx,%es
536
537 SerialLoop_loop:
538         movw    $PORTADDR_BASE,%bx
539         addb    %ah,%bl
540         movw    %es:(%bx),%bx
541         testw   %bx,%bx
542         jz      SerialLoop_noport       /* now we have port base in BX */
543         movb    $1,%ch
544         movb    %ah,%cl
545         rolb    %cl,%ch
546         testb   %ch,%ds:(SerialEnable-START)
547         jz      SerialLoop_noport       /* disabled port */
548         pushw   %ax                     /* push CHARACTER and AH(port offset), S=2 */
549         cmpb    $'%',%al
550         jnz     SerialLoop_noInit
551
552 /* Serial Init */
553         leaw    UART_IER(%bx),%dx       /* DX=+1, UAT_IER - interrupt enable */
554         xorb    %al,%al                 /* NO interrupts */
555         outb    %al,%dx
556         incw    %dx
557         incw    %dx             /* DX=+3, UART_LCR - used as divisor enable */
558         movb    $SERIAL_LCR_INIT | UART_LCR_DLAB,%al
559         outb    %al,%dx
560         movw    %bx,%dx         /* DX=+0, UART_DLL - divisor LOW */
561         movb    $(SERIAL_DIVISOR & 0xFF),%al
562         outb    %al,%dx
563         incw    %dx             /* DX=+1, UART_DLM - divisor HIGH */
564         movb    $(SERIAL_DIVISOR >> 8),%al
565         outb    %al,%dx
566         incw    %dx
567         incw    %dx             /* DX=+3, UART_LCR - line control */
568         movb    $SERIAL_LCR_INIT,%al
569         outb    %al,%dx
570         incw    %dx             /* DX=+4, UART_MCR - modem control */
571         movb    $SERIAL_MCR_INIT,%al
572         outb    %al,%dx
573         incw    %dx             /* DX=+5, UART_LSR - line status */
574         inb     %dx,%al
575         incb    %al
576         jz      PrintChar_serial_invalidPort            /* LSR port is 0xFF - no device on the bus */
577
578 #ifdef SERIAL_REQUIRE_DSR
579         incw    %dx             /* DX=+6, UART_MSR - modem status */
580         xorw    %cx,%cx                 /* Try ~ 60msec for DSR transition delayd by pure wiring after our DTR */
581 PrintChar_serialWaitDSR:
582         inb     %dx,%al
583         andb    $UART_MSR_DSR,%al       /* we MUST have AL==0 when passing to invalidPort ! */
584         jnz     PrintChar_serialSend
585         loop    PrintChar_serialWaitDSR
586         jmp     PrintChar_serial_invalidPort
587 #endif /* SERIAL_REQUIRE_DSR */
588
589 SerialLoop_loop_jump1:
590         jmp     SerialLoop_loop
591
592 SerialLoop_noInit:              /* still CHARACTER and AH(port offset) on stack, S=2 */
593 PrintChar_serialSend:
594         movb    $SERIAL_SENDWAIT,%ah
595 PrintChar_serialSend_wait:
596         leaw    UART_LSR(%bx),%dx       /* UART_LSR - line status */
597         inb     %dx,%al
598         andb    $UART_LSR_THRE,%al      /* test transmitter-buffer-empty bit */
599         jnz     PrintChar_serialSend_free       /* we MUST have AL==0 when passing to invalidPort ! */
600         loop    PrintChar_serialSend_wait
601         decb    %ah                     /* out-loop count SERIAL_SENDWAIT */
602         jnz     PrintChar_serialSend_wait
603 PrintChar_serial_invalidPort:
604         leaw    UART_MCR(%bx),%dx       /* UART_LSR - line status */
605         outb    %al,%dx                 /* assumed AL==0: turn off DTR & RTS of the failing port */
606         movb    %ds:(SerialEnable-START),%ah
607         pushw   %ax                     /* pushed AH(SerialEnable), S=3 */
608         movb    %al,%ds:(SerialEnable-START)    /* assumed AL==0; disable temporarily complete serial output */
609         pushw   %si             /* save SI, S=4 */
610         pushw   %bx                     /* port base to print out */
611         movw    $SerialPortError_Msg-START,%si
612         call    PrintString
613         popw    %si             /* recover SI, S=3 */
614         popw    %bx                     /* restored BH=AH(SerialEnable), S=2 */
615         popw    %ax                     /* restored CHARACTER and AH(port offset), S=1 */
616         movb    %ah,%cl
617         movb    $0xFE /* ==~1 */,%ch
618         rolb    %cl,%ch         /* masking-out pattern */
619         andb    %ch,%bh         /* mask-out the original SerialEnable left in BH */
620         movb    %bh,%ds:(SerialEnable-START)    /* disable the failed port for futher serial dumping */
621         jmp     SerialLoop_noport
622
623 PrintChar_serialSend_free:
624         movw    %bx,%dx                 /* UART_TX - xmit buffer */
625         popw    %ax                     /* restored CHARACTER and AH(port offset), S=1 */
626         outb    %al,%dx                 /* final character transmit */
627
628 SerialLoop_noport:
629         inc     %ah
630         inc     %ah                     /* skip by two bytes of PORTADDR_BASE entry offset */
631         cmp     $4*2,%ah
632         jne     SerialLoop_loop_jump1
633         popw    %es                     /* pop ES, S=0 */
634 #ifndef OUTPUT_STORE_DISK
635         ret
636 #else
637 /* FALLTHRU */
638 #endif
639 #endif /* SERIAL_BAUDRATE */
640
641 /* OutputStore handling code */
642 /*****************************/
643
644 #ifdef OUTPUT_STORE_DISK
645
646 #if OUTPUT_STORE_DISK!=0x00
647 #error "int13sniff WILL destroy the data on OUTPUT_STORE_DISK!!! Are you sure?"
648 #endif
649
650 OutputStorePrintChar:
651
652 /* Function assumes DS == CS, it preserves SI, DI, ES. */
653 /* Function expects character to print in AL. */
654
655         testb   $OUTPUT_STORE_SerialEnable,%ds:(SerialEnable-START)
656         jz      Return3
657 OS_NotDisabled:
658         cmp     $13,%al                         /* we completely ignore and filter-out all '\r' */
659         je      Return3
660         pushw   %es                     /* SAVE %ES */
661         pushw   %di                     /* SAVE %DI */
662         pushw   %si                     /* SAVE %SI */
663         movw    %ds:(OutputStoreBufPtr-START),%di
664         pushw   %cs
665         popw    %es                     /* ES=CS */
666         stosb
667 OutputStoreTerminate:           /* we will terminate the OutputStoreBuf at the given %DI position */
668         movw    %di,%ds:(OutputStoreBufPtr-START)
669         movb    $OUTPUT_STORE_EOF,%ds:(%di)
670         cmpb    $0,%ds:(OutputStoreFlushEnable-START)
671         jz      Return2pop_jump1                /* we cannot yet call CallJumpVector0x13 */
672         cmpb    $10,%al
673         je      OutputStoreFlush                /* always flush bufer on message newline */
674         cmpw    $(OutputStoreBuf-START)+0x200,%di
675         jnc     OutputStoreFlush
676 Return2pop_jump1:
677         jmp     Return2pop
678
679 Return3:
680         ret
681
682 OutputStoreFlush:
683         movw    $OUTPUT_STORE_WRITE_RETRIES,%bp
684 OS_RetryWrite:
685         mov     $0x08,%ah                       /* %AH=get drive geometry, WARNING: DESTROYS %DI! */
686         mov     $OUTPUT_STORE_DISK,%dl
687         CallJumpVector0x13              /* now %DH=maximum heads, %CX=maximum cylinder&sector */
688         jc      OS_MediaOver
689         movw    %cx,%bx
690         xchg    %bh,%bl
691         rol     $1,%bh
692         rol     $1,%bh
693         andb    $0x03,%bh               /* now %BX==# of cylinders */
694         andb    $0x3F,%cl               /* now %CL==# of sectors */
695         pushw   %cx             /* SAVE LOW==# of sectors */
696         inc     %dh                     /* now %DH==# of heads */
697         movb    %dh,%al
698         mulb    %cl                     /* now %AX==# of sectors in cylinder */
699         movw    %ax,%cx
700         /* now we have %CX==# of sectors in cylinder, %BX=# of cylinders */
701         movw    %cs:(OutputStoreAddress-START+0),%ax
702         movw    %cs:(OutputStoreAddress-START+2),%dx            /* %DX:%AX==OutputStoreAddress */
703         divw    %cx                                     /* now %AX==cylinder, %DX==head&sector */
704         cmp     %ax,%bx
705         popw    %bx                     /* RESTORE ->%BL==# of sectors */
706         jc      OS_MediaOver    /* cylinders exceeded */
707         xchg    %ax,%dx
708         divb    %bl                     /* now %AL==head, %AH=0-based sector (and %DX==cylinder) */
709         incb    %ah                                     /* now %AL==head, %AH=1-based sector (and %DX==cylinder) */
710         testb   $0xC0,%ah
711         jnz     OS_MediaOver
712         testb   $0xFC,%dh
713         jnz     OS_MediaOver
714         movb    %ah,%cl
715         movb    %dl,%ch
716         rorb    $1,%dh
717         rorb    $1,%dh
718         orb     %dh,%cl                 /* now %CX==cylinder&sector in BIOS format */
719         movb    %al,%dh                 /* now %DH==head */
720         pushw   %cs
721         popw    %ds                     /* DS=CS */
722         movb    $OUTPUT_STORE_DISK,%dl
723         movw    $0x0301,%ax                     /* %AH=write sectors, %AL=1 sector */
724         movw    $(OutputStoreBuf-START),%bx
725         pushw   %cs
726         popw    %es                     /* ES=CS */
727         CallJumpVector0x13
728         jnc     OS_WriteOK
729         movw    %ax,%es         /* %ES=Write16 error code */
730         xorb    %ah,%ah                         /* %AH=reset drive */
731         CallJumpVector0x13
732         decw    %bp
733         jnz     OS_RetryWrite
734         andb    $~OUTPUT_STORE_SerialEnable,%ds:(SerialEnable-START)    /* OutputStorePrintChar got DISABLED here */
735         pushw   %es     /* Write16 error code, for secondary "SnifferErrTail_MSG" */
736                         /* now parameters for "Common16disk_Msg": */
737         pushw   %bx     /* buf 2nd */
738         pushw   %cs     /* buf 1st (%ES has been destroyed by "Write16 error code" */
739         movb    $0x01,%al       /* "count" has been destroyed by "reset disk" call */
740         pushw   %ax     /* count */
741         pushw   %dx     /* head */
742         pushw   %cx     /* CX<sec/cyl> */
743         pushw   %dx     /* drive */
744
745 OS_MediaOver:
746         movw    $OutputFailedWrite_Msg-START,%si
747         call    PrintString
748         movw    $Common16disk_Msg-START,%si
749         call    PrintString_noPref              /* pops up 6*2 bytes (6 words) */
750         movw    $SnifferErrTail_MSG-START,%si
751         call    PrintString_noPref              /* pops up 1*2 bytes (1 word ) */
752 Return2pop:
753         popw    %si             /* RESTORE %SI */
754         popw    %di             /* RESTORE %DI */
755         popw    %es             /* RESTORE %ES */
756 Return2:        ret
757
758 OS_WriteOK:
759         cmpw    $(OutputStoreBuf-START)+0x200,%ds:(OutputStoreBufPtr-START)
760         jc      Return2pop                      /* buffer is not yet filled */
761         incw    %ds:(OutputStoreAddress-START+0)
762         jnz     OS_IncAddrNotWordCarry
763         incw    %ds:(OutputStoreAddress-START+2)
764 OS_IncAddrNotWordCarry:
765         movw    $OutputStoreBuf-START,%di
766         pushw   %di
767         xorw    %ax,%ax
768         movw    $0x200/2,%cx
769         rep     stosw                   /* OutputStore got cleared */
770         popw    %di
771         movb    $10,%al                         /* we want to immediately Flush even the new sector */
772         jmp     OutputStoreTerminate
773
774 #endif /* OUTPUT_STORE_DISK */
775
776 /**************************************************************/
777 /* Section for INT13 sniffing                                 */
778 /* THIS point may start to be after 0x200 boundary            */
779 /**************************************************************/
780
781 SniffFunction0x13:
782         pushw   %ax     /* trash */
783         pushw   %ds
784         pushALL
785
786         cmpb    $0x00,%ah       /* reset */
787         jne     SF13_not00
788         movw    $JumpVector0x13popa-START,%ax
789         pushw   %ax     /* return address */
790         pushw   %dx     /* drive */
791         movw    $SF13_00_Msg-START,%si
792 JumpVector0x13printStringPopa:
793         call    PrintString
794         jmp     PrintTrailNL
795
796 SF13_not00:
797         cmpb    $0x02,%ah       /* read16 */
798         jne     SF13_not02
799         pushw   %bx     /* buf 2nd */
800         pushw   %es     /* buf 1st */
801         pushw   %ax     /* count */
802         pushw   %dx     /* head */
803         pushw   %cx     /* CX<sec/cyl> */
804         pushw   %dx     /* drive */
805         movw    $SF13_02_Msg-START,%si
806         call    PrintString
807 Sniffer13bottomStdHalf:
808         call    CallVector0x13
809         movw    $SnifferOKTail_Msg-START,%si
810         jnc     SF13_not00_tail         /* ...if CY is SET */
811 Sniffer13DumpErrorAH:
812         movw    $SnifferErrTail_MSG-START,%si
813         pushw   %ax
814 SF13_not00_tail:
815 Sniffer13iretPrintStringFinal:
816         call    PrintString_noPref
817         popALL
818         popw    %ds
819         incw    %sp
820         incw    %sp     /* trash discarded */
821         iret
822
823 SF13_not02:
824         cmpb    $0x41,%ah       /* presence32 */
825         jne     SF13_not41
826         cmpw    $0x55AA,%bx
827         jne     SF13_not41
828         pushw   %dx     /* drive */
829         movw    $SF13_41_Msg-START,%si
830         call    PrintString
831         call    CallVector0x13
832         cmp     $0xAA55,%bx
833         jne     Sniffer13DumpErrorAH
834         pushw   %cx     /* supports */
835         pushw   %ax     /* version */
836         movw    $SF13_41_out_Msg-START,%si
837         jmp     Sniffer13iretPrintStringFinal
838
839 CallVector0x13:
840         popw    %ax     /* return address */
841         pushw   %bp
842         movw    %sp,%bp
843         movw    %ax,%ss:2/*%bp*/+PUSHALL_SIZE+2/*%ds*/(%bp)     /* store %ax to 'trash' */
844         popw    %bp
845         popALL
846         popw    %ds
847         CallJumpVector0x13
848         pushw   %ds
849         pushALL                 /* stack is back to normal NOW */
850         pushw   %bp             /* trash - just to prepare return address16 */
851         pushw   %ax
852         pushw   %bp
853         movw    %sp,%bp
854         movw    %ss:2/*%bp*/+2/*%ax*/+2/*return16*/+PUSHALL_SIZE+2/*%ds*/(%bp),%ax
855         movw    %ax,%ss:2/*%bp*/+2/*ax*/(%bp)
856         pushf
857         pop     %ax
858         movw    %ax,%ss:2/*%bp*/+2/*%ax*/+2/*return16*/+PUSHALL_SIZE+2/*%ds*/+2/*trash*/+4/*ret-seg:offs*/(%bp)
859         popw    %bp
860         popw    %ax
861         ret                     /* to prepared return16 and now will be stack in normal again */
862
863 SF13_not41:
864         cmpb    $0x42,%ah       /* read32 */
865         je      SF13_do42
866         jmp     JumpVector0x13popa      /* too far for conditional-jump */
867
868 SF13_do42:
869         movb    %ds:2(%si),%al  /* count */
870         pushw   %ax
871         pushw   %ds:8(%si)      /* LBA32 sector LOWEST */
872         pushw   %ds:8+2(%si)    /* LBA32 sector LOWER */
873         pushw   %ds:8+4(%si)    /* LBA32 sector HIGHER */
874         pushw   %ds:8+6(%si)    /* LBA32 sector HIGHEST */
875         pushw   %dx             /* drive */
876         movw    $SF13_42_Msg-START,%si
877         call    PrintString     /* first half of the entry-message */
878
879         movw    %sp,%bp
880         movw    %ss:PUSHALL_SI(%bp),%si
881         movw    %ss:PUSHALL_SIZE(%bp),%ds       /* restore DS:SI packet */
882
883         movw    %ds:4(%si),%ax          /* buf16 offset */
884         pushw   %ax             /* buf16 offset */
885         andw    %ds:4+2(%si),%ax        /* buf16 segment */
886         pushw   %ds:4+2(%si)    /* buf16 segment */
887         incw    %ax
888         movw    $SF13_42_buf16_Msg-START,%si
889         jnz     SF13_42_buf16           /* buf16 was NOT 0xFFFF:0xFFFF => jump as OK */
890         addw    $4,%sp          /* drop buf16 address seg:offs */
891         pushw   %ds:0x10(%si)   /* 64-bit buffer LOWEST */
892         pushw   %ds:0x10+2(%si) /* 64-bit buffer LOWER */
893         pushw   %ds:0x10+4(%si) /* 64-bit buffer HIGHER */
894         pushw   %ds:0x10+6(%si) /* 64-bit buffer HIGHEST */
895         movw    $SF13_42_buf64_Msg-START,%si
896
897 SF13_42_buf16:  /* too far for conditional-jump */
898         call    PrintString_noPref
899         jmp     Sniffer13bottomStdHalf
900
901 JumpVector0x13popa:
902         popALL
903         popw    %ds
904         incw    %sp
905         incw    %sp     /* trash discarded */
906 JumpVector0x13:
907         .byte   0xEA    /* ljmp */
908 OrigVector0x13:
909         .skip   4
910
911 /* Serial support upper half initialization messages */
912 /*****************************************************/
913
914 #ifdef SERIAL_BAUDRATE
915
916 SerialPortError_Msg:
917         .asciz  "SerialPort \xF3 error: stopping its communication\r\n"
918
919 SerialHelloPort_Msg:
920         .asciz  " \xF3"
921
922 #endif /* SERIAL_BAUDRATE */
923
924
925 /* Main upper half initialization messages */
926 /*******************************************/
927
928 HelloMsg:
929         .ascii  "INT13-Sniff, version ",VERSION,", RCS revision ",REVISION
930 #ifdef OUTPUT_STORE_DISK
931         .ascii  ", Output Store on disk 0x"
932         .byte   BYTE_TO_HEX(OUTPUT_STORE_DISK)
933 #endif
934 #ifdef SERIAL_BAUDRATE
935         .ascii  ", using serial ports:"
936 #else
937         .byte   13,10
938 #endif
939         .byte   0
940 BadSignatureMsg:
941         .asciz  "Disk 0x80 has invalid signature!"
942
943
944 /* Interrupt sniffing messages */
945 /*******************************/
946
947 Interrupt0x18Msg:
948         .asciz  "Interrupt 0x18 - Failed boot!"
949 SF13_00_Msg:
950         .asciz  "Reset(drv=\xF1)"
951 SF13_41_Msg:
952         .asciz  "Presence32(drv=\xF1)"
953 SF13_41_out_Msg:
954         .ascii  "=(version=\xF2,supports=\xF3)"
955         /* fallthru */
956 SnifferOKTail_Msg:
957         .ascii  " OK"
958         .byte   13,10,0
959 SF13_42_Msg:
960         .asciz  "Read32(drv=\xF1,LBA32=\xF3\xE3\xE3\xE3,count=\xF1,buf="
961 SF13_42_buf16_Msg:
962         .asciz  "\xF3:\xF3)"
963 SF13_42_buf64_Msg:
964         .asciz  "\xF3\xE3\xE3\xE3)"
965
966
967 /* Output Store messages / variables */
968 /*************************************/
969 #ifdef OUTPUT_STORE_DISK
970
971 OutputFailedWrite_Msg:
972         .asciz  "Output Store error, stopping store: Write"
973
974 OutputStoreBufPtr:
975         .word   OutputStoreBufSpaceStart-START
976 OutputStoreAddress:
977 #ifdef OUTPUT_STORE_ADDRESS
978         .long   OUTPUT_STORE_ADDRESS
979 #else
980         .long   (OutputStoreBuf-START)/0x200
981 #endif
982 OutputStoreFlushEnable:
983         .byte   0               /* disable calling of JumpVector0x13 as it is not functional yet */
984
985 #endif
986 /**************************************************************/
987 /* Sectors finalisation                                       */
988 /**************************************************************/
989
990 #ifndef OUTPUT_STORE_DISK
991 ALLOC_END:
992 #endif
993
994         MYORG(ROUND_UP(.+2-START,0x200)-2)
995 Sector2_MagicBuf:
996         .word   SECTOR2_MAGIC
997
998 #ifdef OUTPUT_STORE_DISK
999 OutputStoreBuf:
1000 #endif
1001         .ascii  "\n<OuTpUt_sToRe>\n"
1002 #ifdef OUTPUT_STORE_DISK
1003 OutputStoreBufSpaceStart:
1004         .ascii  "Buffer empty, no data stored yet.\n"
1005 #else
1006         .ascii  "OUTPUT_STORE_DISK not defined, Output Store disabled!\n"
1007 #endif
1008         .byte   OUTPUT_STORE_EOF
1009
1010         MYORG(ROUND_UP(.-START,0x200))  /* WARNING, we may overfull the buffer by +1 bytes, see NOTE_1 */
1011
1012 #ifdef OUTPUT_STORE_DISK
1013         .equ    ALLOC_END,.+1           /* we need one 'trash' byte for exceeding OUTPUT_STORE_EOF */
1014 #endif
1015
1016 SECTORS_END:
1017
1018 /* vi:ts=8:sw=8
1019  */