summaryrefslogtreecommitdiff
path: root/rtl/go32v2/exceptn.as
blob: 545656ed4b9c5f7e8634e3583a3d342dcc22c0b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
/* Copyright (C) 1994, 1995 Charles Sandmann (sandmann@clio.rice.edu)
 * This file maybe freely distributed and modified as long as copyright remains.
 */

  EAX = 0
  EBX = 4
  ECX = 8
  EDX = 12
  ESI = 16
  EDI = 20
  EBP = 24
  ESP = 28
  EIP = 32
  EFLAGS = 36
  CS = 40
  DS = 42
  ES = 44
  FS = 46
  GS = 48
  SS = 50
  ERRCODE = 52
  EXCEPNO = 56
  PREVEXC = 60
/* Length 64 bytes plus non-used FPU */
        .data
        .balign 8
        .comm   exception_stack, 8000

        .text
        .balign 16,,7
   .macro EXCEPTION_ENTRY number
        pushl   \number
        jmp     exception_handler
   .endm

        .global ___djgpp_exception_table
___djgpp_exception_table:
EXCEPTION_ENTRY $18
EXCEPTION_ENTRY $19
EXCEPTION_ENTRY $0
EXCEPTION_ENTRY $1
EXCEPTION_ENTRY $2
EXCEPTION_ENTRY $3
EXCEPTION_ENTRY $4
EXCEPTION_ENTRY $5
EXCEPTION_ENTRY $6
EXCEPTION_ENTRY $7
EXCEPTION_ENTRY $8
EXCEPTION_ENTRY $9
EXCEPTION_ENTRY $10
EXCEPTION_ENTRY $11
EXCEPTION_ENTRY $12
EXCEPTION_ENTRY $13
EXCEPTION_ENTRY $14
EXCEPTION_ENTRY $15
EXCEPTION_ENTRY $16
EXCEPTION_ENTRY $17

/*      This code is called any time an exception occurs in the 32 bit protected
;*      mode code.  The exception number is pushed on the stack.  This is called
;*      on a locked stack with interrupts disabled.  Don't try to terminate.
;*
;*      [   *   |   SS  ]       * Don't modify
;*      [      ESP      ]
;*      [    EFLAGS     ]
;*      [   *   |   CS  ]       * Don't modify
;*      [      EIP      ]
;*      [   ERR CODE    ]
;*      [   *   |RET CS*]       * Don't modify
;*      [   RET EIP*    ]       * Don't modify
;*      [  EXCEPTION #  ]       (And later EBP)
;*/
/* ;WARNING WARNING WARNING
   ;The mechanism for passing signals between the debugger
   ;and the debuggee relies on the *exact* instructions between
   ;EXCEPTION_ENTRY($13) above and "cmpb $0, forced" instruction
   ;below!  These instructions are stored in forced_test[] buffer
   ;in src/debug/common/dbgcom.c.  Do NOT change anything between
   ;these two instructions, or you will break signal support in
   ;the debuggers!!  */
exception_handler:
        pushl   %ebx
        pushl   %ds
        .byte   0x2e                            /* CS: */
        cmpb    $0, forced
        je      not_forced
        call    limitFix
        .byte   0x2e                            /* CS: */
        movzbl  forced,%ebx
        movl    %ebx,8(%esp)                    /* replace EXCEPNO */
        cmpb    $0x75, %bl
        jne     not_forced
        movzwl    ___djgpp_fpu_state,%ebx
        movl    %ebx,20(%esp)                   /* set ERRCODE to FPU state */
not_forced:
        movw    %cs:___djgpp_our_DS, %ds
        movl    $0x10000, forced                /* its zero now, flag inuse */
        movl    $exception_state, %ebx
        popl    DS(%ebx)
        popl    EBX(%ebx)
        popl    EXCEPNO(%ebx)
        movl    %esi, ESI(%ebx)
        movl    %edi, EDI(%ebx)
        movl    %ebp, EBP(%ebx)
        movl    %eax, EAX(%ebx)
        movl    %ecx, ECX(%ebx)
        movl    %edx, EDX(%ebx)
        movw    %es, ES(%ebx)
        movw    %fs, FS(%ebx)
        movw    %gs, GS(%ebx)
        movl    ___djgpp_exception_state_ptr, %eax
        movl    %eax, PREVEXC(%ebx)

/* Stack clean at this point, DS:[EBX] points to exception_state, all
   register information saved.  Now get the info on stack. */

        pushl   %ebp
        movl    %esp, %ebp      /* load ebp with stack for easy access */

        movl    12(%ebp), %eax
        movl    %eax, ERRCODE(%ebx)
        movl    16(%ebp), %eax
        movl    %eax, EIP(%ebx)
        movl    20(%ebp), %eax
        movw    %ax, CS(%ebx)
        movl    24(%ebp), %eax
        movl    %eax, EFLAGS(%ebx)
        andb    $0xfe, %ah                      /* Clear trace flag */
        movl    %eax, 24(%ebp)                  /* and restore on stack */

        movl    28(%ebp), %eax
        movl    %eax, ESP(%ebx)
        movl    32(%ebp), %eax
        movw    %ax, SS(%ebx)

        movl    $dpmi_exception_proc1, 16(%ebp)         /* where to return */
        movw    %cs, 20(%ebp)

/* Change to our local stack on return from exception (maybe stack exception) */
        movw    %ds, %ax
        cmpb    $12,EXCEPNO(%ebx)               /* Stack fault ? */
        je      1f
        cmpw    %ax,32(%ebp)
        je      stack_ok
        .byte   0x2e                            /* CS: */
        movw    ___djgpp_ds_alias,%di
        cmpw    %di,32(%ebp)    /* if it's DS alias, switch to normal DS */
        jne     1f
        movw    %ax,32(%ebp)
        jmp     stack_ok
1:      movl    $exception_stack+8000, 28(%ebp)
        movw    %ax, 32(%ebp)
stack_ok:
/* Now copy the exception structure to the new stack before returning */
        movw    %ax, %es
        movl    %ebx,%esi
        movl    28(%ebp), %edi
        subl    $92, %edi                       /* 64 plus extra for longjmp */
        movl    %edi, 28(%ebp)
        movl    %edi, ___djgpp_exception_state_ptr
        movl    $16, %ecx
        cld
        rep
        movsl

        movl    EAX(%ebx), %eax                         /* restore regs */
        movl    ESI(%ebx), %esi
        movl    EDI(%ebx), %edi
        movl    ECX(%ebx), %ecx
        movw    ES(%ebx), %es
        popl    %ebp
        pushl   EBX(%ebx)
        pushl   DS(%ebx)
        movb    $0, forced+2                            /* flag non-use */
        popl    %ds
        popl    %ebx
        lret

/* Code to fix fake exception, EBX destroyed.  Note, app_DS may == our_DS! */
        .balign 16,,7
limitFix:
        pushl   %eax
        pushl   %ecx
        pushl   %edx
        .byte   0x2e                            /* CS: */
        movl    ___djgpp_app_DS, %ebx           /* avoid size prefix */
        .byte   0x2e                            /* CS: */
        movl    ds_limit, %edx
        movl    %edx, %ecx
        shrl    $16, %ecx
        movw    $0x0008, %ax
        int     $0x31                           /* Set segment limit */
        popl    %edx
        popl    %ecx
        popl    %eax
        ret

/* This local routine preprocesses a return request to the C code.  It checks
   to make sure the DS & SS are set OK for C code.  If not, it sets them up */
        .balign 16,,7
dpmi_exception_proc1:
        cld
        .byte   0x2e                            /* CS: !!! */
        movw    ___djgpp_our_DS, %bx            /* to be sure */
        movw    %bx, %ds
        movw    %bx, %es
        /* Note: SS:ESP should be set properly by exception routine */
        jmp     ___djgpp_exception_processor

/*      This code is called by a user routine wishing to save an interrupt
;*      state.  It will return with a clean stack, our DS,ES,SS.
;*      Minor bug: uses static exception_state for a short window without
;*      interrupts guaranteed disabled.
;*
;*      [    EFLAGS     ]
;*      [   *   |   CS  ]
;*      [      EIP      ]
;*      [  CALLING EIP  ]
;*/

        .balign 16,,7
        .globl  ___djgpp_save_interrupt_regs
___djgpp_save_interrupt_regs:
        pushl   %esi
        pushl   %ds
        movw    %cs:___djgpp_our_DS, %ds
        movl    $exception_state, %esi
        popl    DS(%esi)                /* Trashes ES but OK */
        popl    ESI(%esi)
        movl    %edi, EDI(%esi)
        movl    %ebp, EBP(%esi)
        movl    %eax, EAX(%esi)
        movl    %ebx, EBX(%esi)
        movl    %ecx, ECX(%esi)
        movl    %edx, EDX(%esi)
        popl    %edx                    /* Save calling EIP */
        popl    EIP(%esi)
        popl    %eax
        movw    %ax,CS(%esi)            /* Don't pop, nukes DS */
        popl    EFLAGS(%esi)
        movl    %esp, ESP(%esi)
        movw    %es, ES(%esi)
        movw    %fs, FS(%esi)
        movw    %gs, GS(%esi)
        movw    %ss, SS(%esi)
        movl    ___djgpp_exception_state_ptr, %eax
        movl    %eax, PREVEXC(%esi)
        cld
        movw    %ds, %ax
        movw    %ax, %es
        movw    %ss, %bx
        cmpw    %ax, %bx                        /* is SS = DS ? */
        je      Lss_ok
        movw    %ax, %ss                        /* set new SS:ESP */
        movl    $exception_stack+8000, %esp
Lss_ok: subl    $92, %esp               /* 64 plus extra for longjmp */
        movl    %esp, %edi
        movl    $16, %ecx
        movl    %edi, ___djgpp_exception_state_ptr
        rep
        movsl                                   /* Copy structure to stack */
        jmp     *%edx                           /* A "return" */

        .balign 8               /* We will touch this; it must be locked */
        .global ___djgpp_hw_lock_start
___djgpp_hw_lock_start:
        /* src/debug/common/dbgcom.c knows that `ds_limit' is stored
           4 bytes before `forced' and relies on that.  Do NOT change that! */
ds_limit:                       .long   0
forced:                         .long   0
        .global ___djgpp_cbrk_count
___djgpp_cbrk_count:            .long   0
        .global ___djgpp_timer_countdown
___djgpp_timer_countdown:       .long   0
        .global ___djgpp_our_DS
___djgpp_our_DS:                .word   0
        .global ___djgpp_app_DS
___djgpp_app_DS:                .word   0
        .global ___djgpp_dos_sel
___djgpp_dos_sel:               .word   0
        .global ___djgpp_hwint_flags
___djgpp_hwint_flags:           .word   0
        .global ___djgpp_sigint_key
___djgpp_sigint_key:            .word   0       /* scan code and kb status */
        .global ___djgpp_sigint_mask
___djgpp_sigint_mask:           .word   0       /* kb status mask */
        .global ___djgpp_sigquit_key
___djgpp_sigquit_key:           .word   0
        .global ___djgpp_sigquit_mask
___djgpp_sigquit_mask:          .word   0
        .global ___djgpp_old_kbd
___djgpp_old_kbd:               .long   0,0
        .global ___djgpp_old_timer
___djgpp_old_timer:             .long   0,0
        .global ___djgpp_exception_state_ptr
___djgpp_exception_state_ptr:   .long   0
exception_state:                .space  64
        .global ___djgpp_ds_alias
___djgpp_ds_alias:              .word   0       /* used in dpmi/api/d0303.s (alloc rmcb) */

        .global ___djgpp_fpu_state
___djgpp_fpu_state:             .word   0
        .balign 16,,7
        .global ___djgpp_npx_hdlr
___djgpp_npx_hdlr:
        fnstsw  ___djgpp_fpu_state
        fnclex
        pushl   %eax
        xorl    %eax,%eax
        outb    %al,$0x0f0
        movb    $0x20,%al
        outb    %al,$0x0a0
        outb    %al,$0x020
        movb    $0x75,%al
hw_to_excp:
        call    ___djgpp_hw_exception
        popl    %eax
        sti
        iret

        .balign 16,,7
        .global ___djgpp_kbd_hdlr
___djgpp_kbd_hdlr:
        pushl   %eax
        pushl   %ebx
        pushl   %ds
        .byte   0x2e                            /* CS: */
        testb   $1, ___djgpp_hwint_flags        /* Disable? */
        jne     Lkbd_chain
        movw    %cs:___djgpp_dos_sel, %ds       /* Conventional mem selector */
/*      movw    $0x7021,0xb0f00         */      /* Test code - write to mono */
/* Check Keyboard status bits */
        movb    0x417,%ah                       /* Get KB status byte */
        testb   $1,%ah
        je      6f
        orb     $2,%ah  /* If RShift is set, set LShift as well */
6:
        inb     $0x60,%al                       /* Read the scan code */
99:
        movb    %ah,%bh                         /* Save KB status */
        andb    %cs:___djgpp_sigint_mask, %ah   /* Mask off irrelevant bits */
        cmpw    %cs:___djgpp_sigint_key, %ax    /* Test for SIGINT */
        jne     7f
        movb    $0x79,%bh                       /* SIGINT */
        jmp     98f
7:
        movb    %bh,%ah                         /* Restore KB status */
        andb    %cs:___djgpp_sigquit_mask, %ah  /* Mask off irrelevant bits */
        cmpw    %cs:___djgpp_sigquit_key, %ax   /* Test for SIGQUIT*/
        jne     Lkbd_chain
        movb    $0x7a,%bh                       /* SIGQUIT */
/* Clear interrupt, (later: remove byte from controller?)
        movb    $0x20,%al
        outb    %al,$0x020      */
98:
        movb    %bh,%al
        call    ___djgpp_hw_exception
Lkbd_chain:
        popl    %ds
        popl    %ebx
        popl    %eax
        ljmp    %cs:___djgpp_old_kbd

        .balign 16,,7
        .global ___djgpp_kbd_hdlr_pc98
___djgpp_kbd_hdlr_pc98:
        pushl   %eax
        pushl   %ebx
        pushl   %ds
        .byte   0x2e                            /* CS: */
        testb   $1, ___djgpp_hwint_flags        /* Disable? */
        jne     Lkbd_chain
/* Check CTRL state */
        movw    %cs:___djgpp_dos_sel, %ds       /* Conventional mem selector */
        movb    0x053a,%al                      /* Get KB status byte */
        /* Convert PC98 style status byte to PC/AT style */
        movb    %al,%ah
        andb    $0x09,%ah       /* GRPH(=ALT), SHIFT(=R-Shift) */
        testb   $0x02,%al
        je      981f
        orb     $0x40,%ah       /* CAPS(=Caps Lock) */
981:    testb   $0x10,%al
        je      982f
        orb     $0x04,%ah       /* CTRL(=Ctrl) */
982:    testb   $0x01,%al
        je      983f
        orb     $0x02,%ah       /* SHIFT(=L-Shift) */
983:    testb   $0x04,%al
        je      984f
        orb     $0x20,%ah       /* KANA(=NUM Lock) */
984:    inb     $0x41,%al                       /* Read the scan code */
        jmp     99b

        .balign 16,,7
        .global ___djgpp_timer_hdlr
___djgpp_timer_hdlr:
        .byte   0x2e                            /* CS: */
        cmpl    $0,___djgpp_timer_countdown
        je      4f
        pushl   %ds
        movw    %cs:___djgpp_ds_alias, %ds
        decl    ___djgpp_timer_countdown
        popl    %ds
        jmp     3f
4:
        pushl   %eax
        movb    $0x78,%al
        call    ___djgpp_hw_exception
        popl    %eax
3:
        .byte   0x2e                            /* CS: */
        testb   $4, ___djgpp_hwint_flags        /* IRET or chain? */
        jne     2f
        ljmp    %cs:___djgpp_old_timer
2:
        pushl   %eax
        movb    $0x20,%al                       /* EOI the interrupt */
        outb    %al,$0x020
        popl    %eax
        iret

        /* On entry ES is the DS alias selector */
        .balign 16,,7
        .global ___djgpp_cbrk_hdlr              /* A RMCB handler for 0x1b */
___djgpp_cbrk_hdlr:
        cld
        lodsl                                   /* EAX = DS:[esi] CS:IP */
        movl    %eax, %es:0x2a(%edi)            /* store in structure */
        lodsl                                   /* AX = FLAGS */
        movw    %ax, %es:0x20(%edi)
        addw    $6, %es:0x2e(%edi)              /* Adjust RM SP */
        movb    $0x1b,%al

        .byte   0x2e                            /* CS: */
        testb   $2, ___djgpp_hwint_flags        /* Count, don't kill */
        jne     1f

        call    ___djgpp_hw_exception
        iret
1:
        incl    %es:___djgpp_cbrk_count
        iret

        .global ___djgpp_i24                    /* Int 24 handler if needed */
        .global ___djgpp_iret                   /* Int 23 handler if needed */
___djgpp_i24:
        movb    $3,%al
___djgpp_iret:
        iret

/* Code to stop execution ASAP, EAX destroyed.  Make DS/ES/SS invalid.
   Fake exception value is passed in AL and moved into the "forced" variable.
   This is used to convert a HW interrupt into something we can transfer
   control away from via longjmp or exit(), common with SIGINT, SIGFPE, or
   if we want EIP information on timers. */

        .balign 16,,7
        .global ___djgpp_hw_exception
___djgpp_hw_exception:
        .byte   0x2e                            /* CS: */
        cmpl    $0, forced                      /* Already flagged? */
        jne     already_forced
        pushl   %ebx
        pushl   %ecx
        pushl   %edx
        pushl   %ds
        movw    %cs:___djgpp_our_DS, %ds
        movl    ___djgpp_app_DS, %ebx           /* avoid size prefix */
        lsl     %ebx, %ecx
        movl    %ecx, ds_limit                  /* Save current limit */
        movb    %al, forced                     /* Indicate a fake exception */
        xorl    %ecx, %ecx
        movw    $0xfff, %dx                     /* 4K limit is null page ! */
        movw    $0x0008, %ax
        int     $0x31                           /* Set segment limit */
5:      popl    %ds
        popl    %edx
        popl    %ecx
        popl    %ebx
already_forced:
        ret

        .global ___djgpp_hw_lock_end
___djgpp_hw_lock_end:
        ret                                     /* LD does weird things */

/*
   $Log: exceptn.as,v $
   Revision 1.6  2002/09/08 09:16:15  jonas
     * added closing of comment for logs to avoid warning

   Revision 1.5  2002/09/07 16:01:18  peter
     * old logs removed and tabs fixed

*/