2 * Copyright (c) 1992, 1993, 1996
3 * Berkeley Software Design, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Berkeley Software
18 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * BSDI trap.c,v 2.3 1996/04/08 19:33:08 bostic Exp
32 * $FreeBSD: src/usr.bin/doscmd/trap.c,v 1.7.2.1 2002/04/25 11:04:51 tg Exp $
33 * $DragonFly: src/usr.bin/doscmd/trap.c,v 1.3 2004/01/21 21:48:21 rob Exp $
36 #include <machine/trap.h>
44 ** When the emulator is very busy, it's often common for
45 ** SIGALRM to be missed, leading to missed screen updates.
47 ** We update this counter every time a DOS interrupt is processed and
48 ** if it hits a certain threshold, force an update.
50 ** When updates occur, the counter is zeroed.
52 static int update_counter
= 0;
53 #define BUSY_UPDATES 2000
56 ** handle interrupts passed to us by the kernel
59 fake_int(regcontext_t
*REGS
, int intnum
)
61 if (R_CS
== 0xF000 || (ivec
[intnum
] >> 16) == 0xF000) {
63 intnum
= ((u_char
*)VECPTR(ivec
[intnum
]))[1];
64 debug(D_ITRAPS
| intnum
, "INT %02x:%02x %04x:%04x/%08lx\n",
65 intnum
, R_AH
, R_CS
, R_IP
, ivec
[intnum
]);
67 case 0x2f: /* multiplex interrupt */
68 int2f((regcontext_t
*)®S
->sc
);
70 case 0xff: /* doscmd special */
73 default: /* should not get here */
74 if (vflag
) dump_regs(REGS
);
75 fatal("no interrupt set up for 0x%02x\n", intnum
);
81 debug(D_TRAPS
| intnum
,
82 "INT %02x:%02x [%04lx:%04lx] %04x %04x %04x %04x from %04x:%04x\n",
83 intnum
, R_AH
, ivec
[intnum
] >> 16, ivec
[intnum
] & 0xffff,
84 R_AX
, R_BX
, R_CX
, R_DX
, R_CS
, R_IP
);
87 if ((intnum
== 0x13) && (*(u_char
*)VECPTR(ivec
[intnum
]) != 0xf4)) {
89 char *addr
; /*= (char *)VECPTR(ivec[intnum]);*/
95 addr
= (char *)MAKEPTR(R_CS
, R_IP
);
98 for (i
= 0; i
< 100; i
++) {
99 l
= i386dis(R_CS
, R_IP
, addr
, buf
, 0);
100 printf("%04x:%04x %s\t;",R_CS
,R_IP
,buf
);
101 for (j
= 0; j
< l
; j
++)
102 printf(" %02x", (u_char
)addr
[j
]);
117 if (ivec
[intnum
] == 0) { /* uninitialised interrupt? */
118 if (vflag
) dump_regs(REGS
);
119 fatal("Call to uninitialised interrupt 0x%02x\n", intnum
);
123 * This is really ugly, but when DOS boots, it seems to loop
124 * for a while on INT 16:11 INT 21:3E INT 2A:82
125 * INT 21:3E is a close(), which seems like something one would
126 * not sit on for ever, so we will allow it to reset our POLL count.
128 if (intnum
== 0x21 && R_AX
== 0x3E)
131 /* stack for and call the interrupt in vm86 space */
132 PUSH((R_FLAGS
& ~PSL_I
) | (R_EFLAGS
& PSL_VIF
? PSL_I
: 0), REGS
);
135 R_EFLAGS
&= ~PSL_VIF
; /* disable interrupts */
136 PUTVEC(R_CS
, R_IP
, ivec
[intnum
]);
139 /* make this read a little more intuitively */
140 #define ipadvance(c,n) SET16(c->sc_eip, GET16(c->sc_eip) + n) /* move %ip along */
143 /* entry from NetBSD-style vm86 */
145 sigurg(struct sigframe
*sf
)
147 #define sc (&sf->sf_sc)
155 printf("ivec08 = %08x\n", ivec
[0x08]);
161 switch (VM86_TYPE(sf
->sf_code
)) {
163 intnum
= VM86_ARG(sf
->sf_code
);
166 switch (GET8H(sc
->sc_eax
)) {
168 debug (D_TRAPS
|0x2f, "INT 2F:%04x\n", GET16(sc
->sc_eax
));
170 /* Skip over int 2f:11 */
175 debug (D_TRAPS
|0x2f, "INT 2F:%04x\n", GET16(sc
->sc_eax
));
177 /* Skip over int 2f:43 */
184 fake_int(sc
, intnum
);
187 /*XXXXX failed vector also gets here without IP adjust*/
189 addr
= (u_char
*)MAKEPTR(sc
->sc_cs
, sc
->sc_eip
);
192 debug (D_TRAPS2
, "%04x:%04x [%02x]", GET16(sc
->sc_cs
),
193 GET16(sc
->sc_eip
), addr
[0]);
221 inb(sc
, GET16(sc
->sc_edx
));
225 inx(sc
, GET16(sc
->sc_edx
));
229 outb(sc
, GET16(sc
->sc_edx
));
233 outx(sc
, GET16(sc
->sc_edx
));
238 outsb(sc
, GET16(sc
->sc_edx
));
243 outsx(sc
, GET16(sc
->sc_edx
));
248 insb(sc
, GET16(sc
->sc_edx
));
253 insx(sc
, GET16(sc
->sc_edx
));
256 debug(D_TRAPS2
, "lock\n");
259 case HLT
: /* BIOS entry points populated with HLT */
260 func
= find_callback(GETVEC(sc
->sc_cs
, sc
->sc_eip
));
263 SET16(sc
->sc_eip
, GET16(sc
->sc_eip
) + 1);
269 fatal("unsupported instruction\n");
274 printf("code = %04x\n", sf
->sf_code
);
275 fatal("unrecognized vm86 trap\n");
287 /* entry from FreeBSD, BSD/OS vm86 */
289 sigbus(struct sigframe
*sf
)
292 int tempflags
,okflags
;
296 regcontext_t
*REGS
= (regcontext_t
*)(&sf
->sf_uc
.uc_mcontext
);
298 if (!(R_EFLAGS
& PSL_VM
))
299 fatal("SIGBUS in the emulator\n");
301 if ((int)sf
->sf_siginfo
!= 0) {
302 switch (sf
->sf_uc
.uc_mcontext
.mc_trapno
) {
304 debug(D_TRAPS2
, "Page fault, trying to access 0x%x\n",
306 /* nothing but accesses to video memory can fault for now */
307 if (vmem_pageflt(sf
) == 0)
312 fatal("SIGBUS code %d, trapno: %d, err: %d\n",
313 (int)sf
->sf_siginfo
, sf
->sf_uc
.uc_mcontext
.mc_trapno
,
314 sf
->sf_uc
.uc_mcontext
.mc_err
);
319 addr
= (u_char
*)MAKEPTR(R_CS
, R_IP
);
324 if ((R_EFLAGS
& (PSL_VIP
| PSL_VIF
)) == (PSL_VIP
| PSL_VIF
)) {
329 /* printf("%p\n", addr); fflush(stdout); */
330 debug (D_TRAPS2
, "%04x:%04x [%02x %02x %02x] ", R_CS
, R_IP
,
331 (int)addr
[0], (int)addr
[1], (int)addr
[2]);
333 if ((int)addr
[0] == 0x67) {
335 printf("HERE\n"); fflush(stdout
);
336 printf("addr: %p\n", REGS
); fflush(stdout
);
337 for (i
= 0; i
< 21 * 4; i
++) {
338 printf("%d: %x\n", i
, ((u_char
*)REGS
)[i
]);
341 printf("Trapno, error: %p %p\n", REGS
->sc
.sc_trapno
, REGS
->sc
.sc_err
);
347 switch (addr
[0]) { /* what was that again dear? */
350 debug (D_TRAPS2
, "cli\n");
352 R_EFLAGS
&= ~PSL_VIP
;
356 debug (D_TRAPS2
, "sti\n");
360 if (update_counter
++ > BUSY_UPDATES
)
366 debug (D_TRAPS2
, "pushf <- 0x%lx\n", R_EFLAGS
);
368 PUSH((R_FLAGS
& ~PSL_I
) | (R_EFLAGS
& PSL_VIF
? PSL_I
: 0),
373 R_IP
= POP(REGS
); /* get new cs:ip off the stack */
375 debug (D_TRAPS2
, "iret to %04x:%04x ", R_CS
, R_IP
);
376 /* FALLTHROUGH */ /* 'safe' flag pop operation */
380 fatal("popf/iret in emulator");
384 /* get flags from stack */
385 tempflags
= POP(REGS
);
386 /* flags we consider OK */
387 okflags
= (PSL_ALLCC
| PSL_T
| PSL_D
| PSL_V
);
388 /* keep state of non-OK flags */
389 R_FLAGS
= ((R_FLAGS
& ~okflags
) |
390 /* pop state of OK flags */
391 (tempflags
& okflags
));
393 /* restore pseudo PSL_I flag */
394 IntState
= tempflags
& PSL_I
;
395 debug(D_TRAPS2
, "popf -> 0x%lx\n", R_EFLAGS
);
399 debug(D_TRAPS2
, "ttrap\n");
406 R_IP
+= 2; /* nobody else will do it for us */
409 switch (R_AH
) { /* function number */
411 debug (D_TRAPS
|0x2f, "INT 2F:%04x\n", R_AX
);
412 if (int2f_11(REGS
)) {
413 /* Skip over int 2f:11 */
418 debug (D_TRAPS
|0x2f, "INT 2F:%04x\n", R_AX
);
419 if (int2f_43(REGS
)) {
420 /* Skip over int 2f:43 */
427 fake_int(REGS
, intnum
);
430 case INd
: /* XXX implement in/out */
450 printf("(missed) INSB <- 0x%02x\n",R_DX
);
454 printf("(missed) INSW <- 0x%02x\n",R_DX
);
477 printf("(missed) OUTSB -> 0x%02x\n",R_DX
);
481 printf("(missed) OUTSW -> 0x%02x\n",R_DX
);
486 debug(D_TRAPS2
, "lock\n");
490 case HLT
: /* BIOS entry points populated with HLT */
491 func
= find_callback(MAKEVEC(R_CS
, R_IP
));
493 R_IP
++; /* pass HLT opcode */
495 /* dump_regs(REGS); */
498 if (update_counter
> BUSY_UPDATES
)
503 /* if (R_EFLAGS & PSL_VIF) { */
512 fatal("unsupported instruction\n");
519 #endif /* USE_VM86 */
522 sigtrace(struct sigframe
*sf
)
525 regcontext_t
*REGS
= (regcontext_t
*)(&sf
->sf_uc
.uc_mcontext
);
527 if (R_EFLAGS
& PSL_VM
) {
528 debug(D_ALWAYS
, "Currently in DOS\n");
530 for (x
= 0; x
< 16; ++x
)
531 debug(D_ALWAYS
, " %02x", *(unsigned char *)x
);
534 debug(D_ALWAYS
, "Currently in the emulator\n");
540 sigtrap(struct sigframe
*sf
)
544 regcontext_t
*REGS
= (regcontext_t
*)(&sf
->sf_uc
.uc_mcontext
);
546 if ((R_EFLAGS
& PSL_VM
) == 0) {
548 fatal("%04x:%08x Sigtrap in protected mode\n", R_CS
, R_IP
);
552 if (resettrace(REGS
))
555 #if defined (__FreeBSD__) || defined (__DragonFly__)
556 trapno
= (int)sf
->sf_siginfo
; /* XXX GROSTIC HACK ALERT */
558 trapno
= sc
->sc_trapno
;
560 if (trapno
== T_BPTFLT
)
565 PUSH((R_FLAGS
& ~PSL_I
) | (R_EFLAGS
& PSL_VIF
? PSL_I
: 0), REGS
);
569 PUTVEC(R_CS
, R_IP
, ivec
[intnum
]);
577 breakpoint(struct sigframe
*sf
)
579 regcontext_t
*REGS
= (regcontext_t
*)(&sf
->sf_uc
.uc_mcontext
);
581 if (R_EFLAGS
& PSL_VM
)
583 printf("breakpoint: %04x\n", *(u_short
*)0x8e64);
585 __asm__
volatile("mov 0, %eax");
586 __asm__
volatile(".byte 0x0f"); /* MOV DR6,EAX */
587 __asm__
volatile(".byte 0x21");
588 __asm__
volatile(".byte 0x1b");
595 sigalrm(struct sigframe
*sf
)
597 regcontext_t
*REGS
= (regcontext_t
*)(&sf
->sf_uc
.uc_mcontext
);
602 update_counter
= 0; /* remember we've updated */
603 video_update((regcontext_t
*)®S
->sc
);
611 sigill(struct sigframe
*sf
)
613 regcontext_t
*REGS
= (regcontext_t
*)(&sf
->sf_uc
.uc_mcontext
);
615 fprintf(stderr
, "Signal %d from DOS program\n", sf
->sf_signum
);
617 fatal("%04x:%04x Illegal instruction\n", R_CS
, R_IP
);
622 sigfpe(struct sigframe
*sf
)
624 regcontext_t
*REGS
= (regcontext_t
*)(&sf
->sf_uc
.uc_mcontext
);
626 if (R_EFLAGS
& PSL_VM
) {
628 debug(D_ALWAYS
, "DOS program caused floating point fault\n");
629 /*XXX Look into that !! */
630 fake_int(REGS
, 0); /* call handler XXX rather bogus, eh? */
634 fatal("%04x:%04x Floating point fault in emulator.\n", R_CS
, R_IP
);