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
*/
|