/*
 this file was changed or created for the DOS32 library for DJGPP on 5.10.1996
 new created files are copyright 1996 by C.Lageman, see docs.doc for details
*/
/*
   This file contains the exception handlers and interrupts needed for
   the dos32 library.

   problem: Unter the dos32 environment the IRQs 0-7 and expections 8-15
            use the same interrupt handlers, so we must check in these
            expections, if the called handler is really an expection or
            just an IRQ. In the second case the int is chained down to the
            old handler.
            Of course, this can cause a noticeable (?) slowdown of the machine,
            so installing these handlers or just only the expection 8 (which
            blocks the timer IRQ) can be disabled by __crt0_startup_flags.
   problem: should the exit proc called on an exception program abort
            rather than directly exiting ?
*/
        .file "exceptn.s"
        .text


/*
   this handler should be aligned 16, because it's called very often
*/
.align 16
handler8:
        pushl   %eax
        movl    $___dos32_oldints+0xf*8,%eax
        call    testirq
        pushl   %eax
        movl    $msgexp8,%eax
        jmp     saveregs
handler9:
        pushl   %eax
        movl    $___dos32_oldints+9*8,%eax
        call    testirq
        sub     $4,%esp
        pushl   %eax
        movl    $msgexp9,%eax
        jmp     saveregs
handlera:
        pushl   %eax
        movl    $___dos32_oldints+0xa*8,%eax
        call    testirq
        pushl   %eax
        movl    $msgexpa,%eax
        jmp     saveregs
handlerb:
        pushl   %eax
        movl    $___dos32_oldints+0xb*8,%eax
        call    testirq
        pushl   %eax
        movl    $msgexpb,%eax
        jmp     saveregs
handlerc:
        pushl   %eax
        movl    $___dos32_oldints+0xc*8,%eax
        call    testirq
        pushl   %eax
        movl    $msgexpc,%eax
        jmp     saveregs
handlerd:
        pushl   %eax
        movl    $___dos32_oldints+0xd*8,%eax
        call    testirq
        pushl   %eax
        movl    $msgexpd,%eax
        jmp     saveregs
handlere:
        pushl   %eax
        movl    $___dos32_oldints+0xe*8,%eax
        call    testirq
        pushl   %eax
        movl    $msgexpe,%eax
        jmp     saveregs
handler0:
        pushl   %eax
        movl    $msgexp0,%eax
        jmp     saveregs
handler2:
        pushl   %eax
        movl    $msgexp2,%eax
        jmp     saveregs
handler4:
        pushl   %eax
        movl    $msgexp4,%eax
        jmp     saveregs
handler5:
        pushl   %eax
        movl    $msgexp5,%eax
        jmp     saveregs
handler6:
        pushl   %eax
        movl    $msgexp6,%eax
        jmp     saveregs
handler7:
        pushl   %eax
        movl    $msgexp7,%eax

saveregs:
        pushl   %ds
        cs
        movw    ___dos32_ds,%ds
        movl    %eax,expmsg
/*
    get old ds & save
*/
        popl    %eax
        movl    %eax,regstore+16
/*
    restore eax
*/
        popl    %eax
        movl    %esp,esptemp
        movw    %ss,sstemp
        pushl   %ds
        popl    %ss
        movl    $regstoreend,%esp
        pusha
        pushl   %gs
        pushl   %fs
        pushl   %es
        movl    esptemp,%esp
        movw    sstemp,%ss
        popl    regstore+4
        popl    regstore
        movl    %esp,regstore+12
        popl    regstoreend
        movl    %ss,regstore+8
        

        movl    $expmask,%ecx
        call    dumpmsg
        movl    expmsg,%ecx
        call    dumpmsg

        cld
        movl    $regaddr,%esi
        movl    $regstore,%edx
        xorl    %ecx,%ecx
regs2hex:
        movl    (%esi),%edi
        movl    (%edx),%ebx
        orl     %edi,%edi
        jz      hexdone
        addl    $4,%edx
        addl    $4,%esi
        movb    $8,%cl
inner:
        xorl    %eax,%eax
        shldl   $4,%ebx,%eax
        movb    hexstring(%eax),%al
        ds
        stosb
        shl     $4,%ebx
        decl    %ecx
        jnz     inner
        
        jmp     regs2hex
hexdone:
        movl    $regmask,%ecx
        call    dumpmsg
leaveme:
        movw    $0x4c01,%ax
        int     $0x21

.align  16
testirq:
/*
 eax - address of pointer to old int
  stack:
 esp+16  [   app eflags    ]
 esp+12  [  XXXX  | app cs ]
 esp+8   [     app eip     ]
 esp+4   [       eax       ]
 esp     [    caller eip   ]
*/
        pushl   %eax
        inb     $0x21,%al
        outb    %al,$0x21
        movb    $0x40,%al
        outb    %al,$0x20
        movb    $0x0B,%al
        outb    %al,$0x20
        inb     $0x20,%al
        orb     %al,%al
        popl    %eax
        jz      1f

        cs
        pushl   4(%eax)
        cs
        pushl   (%eax)
/*
   stack:
 esp+26  [    app eflags   ]
 esp+24  [  XXXX  | app cs ]
 esp+16  [     app eip     ]  <--- at this point esp will be after lret
 esp+12  [       eax       ]  removed by lret $8
 esp+8   [    caller eip   ]  removed by lret $8
 esp+4   [  XXXX  | int cs ]
 esp     [     int  eip    ]
*/
        movl    12(%esp),%eax
        lret    $8
1:
        movl    4(%esp),%eax
        ret     $8

dumpmsg:
      movb     $6,%ah
1:    movb     (%ecx),%dl
      orb      %dl,%dl
      jz       2f
      incl     %ecx
      int      $0x21
      jmp      1b
2:    ret


/*
      bios ctrl-break
*/
int1b:
      pushl    %ds
      cs
      movw     ___dos32_ds,%ds
      testb    $1,___dos32_cbreak_mode
      jz       cbreak_exit
      testb    $2,___dos32_cbreak_mode
      jz       1f
      movb     $1,___dos32_cbreak_counter
1:
      popl     %ds
      iret

cbreak_exit:
      movl     $cbreakmsg,%ecx
      call     dumpmsg
      jmp      leaveme

/*
      dos ctrl-c / ctrl - break
      this is faked by just using the identical int1b handler
int23:
      jmp      int1b
*/

/*
      critical error handler with 3 retries (remove retrys ?)
*/
int24:
        testb   $0x80,%ah
        jnz     fail_int24
        pushl   %ds
        pushl   %esi
        cs
        movw    ___dos32_ds,%ds
        cmpb    errordrive,%al
        movl    $error_retries,%esi
        je      1f
        movb    %al,errordrive
        movb    $0,(%esi)
1:      incb    (%esi)
        cmpb    $3,(%esi)
        popl    %esi
        popl    %ds
        ja      fail_int24
        movb    $1,%al
        clc
        lret
fail_int24:
        movb    $3,%al
        clc
        lret

        .data
        .lcomm  esptemp,4
        .lcomm  sstemp,2
errordrive:
        .byte   0xff
        .lcomm  error_retries,1

hexstring:
        .ascii  "0123456789ABCDEF"

        .lcomm   regstore,68
.set regstoreend, regstore + 64

        .lcomm  expmsg,4

regaddr:
        .long   reg1,reg2,reg3,reg4,reg5,reg6,reg7,reg8,reg14
        .long   reg13,reg15,reg10,reg10,reg12,reg11,reg9,reg16,0

msgexp0:
        .asciz  "0 - division by zero"
msgexp2:
        .asciz  "2 - non maskable interrupt"
msgexp4:
        .asciz  "4 - overflow"
msgexp5:
        .asciz  "5 - bound range exceeded$"
msgexp6:
        .asciz  "6 - invalib opcode"
msgexp7:
        .asciz  "7 - coprocessor not aviable"
msgexp8:
        .asciz  "8 - double fault"
msgexp9:
        .asciz  "9 - coprocessor segment overrun"
msgexpa:
        .asciz  "10 - invalid TSS"
msgexpb:
        .asciz  "11 - segment not present"
msgexpc:
        .asciz  "12 - stack exception"
msgexpd:
        .asciz  "13 - general protection fault"
msgexpe:
        .asciz  "14 - page fault"


expmask:
        .asciz  "exception "
regmask:
        .byte   13,10
        .ascii  "CS:EIP - "
reg1:
        .ascii  "MISSING!:"
reg2:
        .ascii  "MISSING!     SS:ESP - "
reg3:
        .ascii  "MISSING!:"
reg4:
        .ascii  "MISSING!"
        .byte   13,10
        .ascii  "DS:  "
reg5:
        .ascii  "MISSING!   ES:  "
reg6:
        .ascii  "MISSING!   FS:  "
reg7:
        .ascii  "MISSING!   GS:  "
reg8:
        .ascii  "MISSING!"
        .byte   13,10
        .ascii  "EAX: "
reg9:
        .ascii  "MISSING!   EBX: "
reg10:
        .ascii  "MISSING!   ECX: "
reg11:
        .ascii  "MISSING!   EDX: "
reg12:
        .ascii  "MISSING!"
        .byte   13,10
        .ascii  "ESI: "
reg13:
        .ascii  "MISSING!   EDI: "
reg14:
        .ascii  "MISSING!   EBP: "
reg15:
        .ascii  "MISSING! FLAGS: "
reg16:
        .ascii  "MISSING!"
        .byte   13,10
        .ascii  "Program abort !"
        .byte   13,10,0

cbreakmsg:
        .ascii  "Exit due to <CTRL-BREAK>"
        .byte   13,10,0

        .global ___dos32_new_ints
___dos32_new_ints:
        .byte   0x1b
        .long   int1b
        .byte   0x23
        .long   int1b
        .byte   0x24
        .long   int24
        .byte   0x0
        .long   handler0
        .byte   0x2
        .long   handler2
        .byte   0x4
        .long   handler4
        .byte   0x5
        .long   handler5
        .byte   0x6
        .long   handler6
        .byte   0x7
        .long   handler7
        .byte   0x9
        .long   handler9
        .byte   0xa
        .long   handlera
        .byte   0xb
        .long   handlerb
        .byte   0xc
        .long   handlerc
        .byte   0xd
        .long   handlerd
        .byte   0xe
        .long   handlere
        .byte   0x8
        .long   handler8
        .byte   0xff
/*
********************    end of exceptn.s **********************************
*/
