libkvm - Add ability to access userspace from kgdb on cores
[dragonfly.git] / usr.bin / doscmd / trap.c
blob126e983b1938c370185cbd34fd856305e846cc50
1 /*
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
7 * are met:
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
16 * Design, Inc.
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
28 * SUCH DAMAGE.
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>
38 #include "doscmd.h"
39 #include "trap.h"
40 #include "tty.h"
41 #include "video.h"
43 /*
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
58 void
59 fake_int(regcontext_t *REGS, int intnum)
61 if (R_CS == 0xF000 || (ivec[intnum] >> 16) == 0xF000) {
62 if (R_CS != 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]);
66 switch (intnum) {
67 case 0x2f: /* multiplex interrupt */
68 int2f((regcontext_t *)&REGS->sc);
69 break;
70 case 0xff: /* doscmd special */
71 emuint(REGS);
72 break;
73 default: /* should not get here */
74 if (vflag) dump_regs(REGS);
75 fatal("no interrupt set up for 0x%02x\n", intnum);
77 return;
80 /* user_int: */
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);
86 #if 0
87 if ((intnum == 0x13) && (*(u_char *)VECPTR(ivec[intnum]) != 0xf4)) {
88 #if 1
89 char *addr; /*= (char *)VECPTR(ivec[intnum]);*/
90 int i, l, j;
91 char buf[100];
93 R_CS = 0x2c7;
94 R_IP = 0x14f9;
95 addr = (char *)MAKEPTR(R_CS, R_IP);
97 printf("\n");
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]);
103 printf("\n");
104 R_IP += l;
105 addr += l;
107 exit (0);
108 #else
109 tmode = 1;
110 #endif
112 #endif
114 if (intnum == 0)
115 dump_regs(REGS);
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)
129 reset_poll();
131 /* stack for and call the interrupt in vm86 space */
132 PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
133 PUSH(R_CS, REGS);
134 PUSH(R_IP, 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 */
142 #ifdef USE_VM86
143 /* entry from NetBSD-style vm86 */
144 void
145 sigurg(struct sigframe *sf)
147 #define sc (&sf->sf_sc)
148 int intnum;
149 u_char *addr;
150 int rep;
151 int port;
152 callback_t func;
154 #if 0
155 printf("ivec08 = %08x\n", ivec[0x08]);
156 #endif
158 if (tmode)
159 resettrace(sc);
161 switch (VM86_TYPE(sf->sf_code)) {
162 case VM86_INTx:
163 intnum = VM86_ARG(sf->sf_code);
164 switch (intnum) {
165 case 0x2f:
166 switch (GET8H(sc->sc_eax)) {
167 case 0x11:
168 debug (D_TRAPS|0x2f, "INT 2F:%04x\n", GET16(sc->sc_eax));
169 if (int2f_11(sc)) {
170 /* Skip over int 2f:11 */
171 goto out;
173 break;
174 case 0x43:
175 debug (D_TRAPS|0x2f, "INT 2F:%04x\n", GET16(sc->sc_eax));
176 if (int2f_43(sc)) {
177 /* Skip over int 2f:43 */
178 goto out;
180 break;
182 break;
184 fake_int(sc, intnum);
185 break;
186 case VM86_UNKNOWN:
187 /*XXXXX failed vector also gets here without IP adjust*/
189 addr = (u_char *)MAKEPTR(sc->sc_cs, sc->sc_eip);
190 rep = 1;
192 debug (D_TRAPS2, "%04x:%04x [%02x]", GET16(sc->sc_cs),
193 GET16(sc->sc_eip), addr[0]);
194 switch (addr[0]) {
195 case TRACETRAP:
196 ipadvance(sc,1);
197 fake_int(sc, 3);
198 break;
199 case INd:
200 port = addr[1];
201 ipadvance(sc,2);
202 inb(sc, port);
203 break;
204 case OUTd:
205 port = addr[1];
206 ipadvance(sc,2);
207 outb(sc, port);
208 break;
209 case INdX:
210 port = addr[1];
211 ipadvance(sc,2);
212 inx(sc, port);
213 break;
214 case OUTdX:
215 port = addr[1];
216 ipadvance(sc,2);
217 outx(sc, port);
218 break;
219 case IN:
220 ipadvance(sc,1);
221 inb(sc, GET16(sc->sc_edx));
222 break;
223 case INX:
224 ipadvance(sc,1);
225 inx(sc, GET16(sc->sc_edx));
226 break;
227 case OUT:
228 ipadvance(sc,1);
229 outb(sc, GET16(sc->sc_edx));
230 break;
231 case OUTX:
232 ipadvance(sc,1);
233 outx(sc, GET16(sc->sc_edx));
234 break;
235 case OUTSB:
236 ipadvance(sc,1);
237 while (rep-- > 0)
238 outsb(sc, GET16(sc->sc_edx));
239 break;
240 case OUTSW:
241 ipadvance(sc,1);
242 while (rep-- > 0)
243 outsx(sc, GET16(sc->sc_edx));
244 break;
245 case INSB:
246 ipadvance(sc,1);
247 while (rep-- > 0)
248 insb(sc, GET16(sc->sc_edx));
249 break;
250 case INSW:
251 ipadvance(sc,1);
252 while (rep-- > 0)
253 insx(sc, GET16(sc->sc_edx));
254 break;
255 case LOCK:
256 debug(D_TRAPS2, "lock\n");
257 ipadvance(sc,1);
258 break;
259 case HLT: /* BIOS entry points populated with HLT */
260 func = find_callback(GETVEC(sc->sc_cs, sc->sc_eip));
261 if (func) {
262 ipadvance(sc,);
263 SET16(sc->sc_eip, GET16(sc->sc_eip) + 1);
264 func(sc);
265 break;
267 default:
268 dump_regs(sc);
269 fatal("unsupported instruction\n");
271 break;
272 default:
273 dump_regs(sc);
274 printf("code = %04x\n", sf->sf_code);
275 fatal("unrecognized vm86 trap\n");
278 out:
279 if (tmode)
280 tracetrap(sc);
281 #undef sc
282 #undef ipadvance
285 #else /* USE_VM86 */
287 /* entry from FreeBSD, BSD/OS vm86 */
288 void
289 sigbus(struct sigframe *sf)
291 u_char *addr;
292 int tempflags,okflags;
293 int intnum;
294 int port;
295 callback_t func;
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) {
303 case T_PAGEFLT:
304 debug(D_TRAPS2, "Page fault, trying to access 0x%x\n",
305 sf->sf_addr);
306 /* nothing but accesses to video memory can fault for now */
307 if (vmem_pageflt(sf) == 0)
308 goto out;
309 /* FALLTHROUGH */
310 default:
311 dump_regs(REGS);
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);
315 /* NOTREACHED */
319 addr = (u_char *)MAKEPTR(R_CS, R_IP);
321 if (tmode)
322 resettrace(REGS);
324 if ((R_EFLAGS & (PSL_VIP | PSL_VIF)) == (PSL_VIP | PSL_VIF)) {
325 resume_interrupt();
326 goto out;
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]);
332 #if 0
333 if ((int)addr[0] == 0x67) {
334 int i;
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]);
339 fflush(stdout);
341 printf("Trapno, error: %p %p\n", REGS->sc.sc_trapno, REGS->sc.sc_err);
342 fflush(stdout);
343 dump_regs(REGS);
345 #endif
347 switch (addr[0]) { /* what was that again dear? */
349 case CLI:
350 debug (D_TRAPS2, "cli\n");
351 R_IP++;
352 R_EFLAGS &= ~PSL_VIP;
353 break;
355 case STI:
356 debug (D_TRAPS2, "sti\n");
357 R_IP++;
358 R_EFLAGS |= PSL_VIP;
359 #if 0
360 if (update_counter++ > BUSY_UPDATES)
361 sigalrm(sf);
362 #endif
363 break;
365 case PUSHF:
366 debug (D_TRAPS2, "pushf <- 0x%lx\n", R_EFLAGS);
367 R_IP++;
368 PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0),
369 REGS);
370 break;
372 case IRET:
373 R_IP = POP(REGS); /* get new cs:ip off the stack */
374 R_CS = POP(REGS);
375 debug (D_TRAPS2, "iret to %04x:%04x ", R_CS, R_IP);
376 /* FALLTHROUGH */ /* 'safe' flag pop operation */
378 case POPF:
379 /* XXX */
380 fatal("popf/iret in emulator");
382 if (addr[0] == POPF)
383 R_IP++;
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);
396 break;
398 case TRACETRAP:
399 debug(D_TRAPS2, "ttrap\n");
400 R_IP++;
401 fake_int(REGS, 3);
402 break;
404 case INTn:
405 intnum = addr[1];
406 R_IP += 2; /* nobody else will do it for us */
407 switch (intnum) {
408 case 0x2f:
409 switch (R_AH) { /* function number */
410 case 0x11:
411 debug (D_TRAPS|0x2f, "INT 2F:%04x\n", R_AX);
412 if (int2f_11(REGS)) {
413 /* Skip over int 2f:11 */
414 goto out;
416 break;
417 case 0x43:
418 debug (D_TRAPS|0x2f, "INT 2F:%04x\n", R_AX);
419 if (int2f_43(REGS)) {
420 /* Skip over int 2f:43 */
421 goto out;
423 break;
425 break;
427 fake_int(REGS, intnum);
428 break;
430 case INd: /* XXX implement in/out */
431 R_IP += 2;
432 port = addr[1];
433 inb(REGS, port);
434 break;
435 case IN:
436 R_IP++;
437 inb(REGS,R_DX);
438 break;
439 case INX:
440 R_IP++;
441 inx(REGS,R_DX);
442 break;
443 case INdX:
444 R_IP += 2;
445 port = addr[1];
446 inx(REGS, port);
447 break;
448 case INSB:
449 R_IP++;
450 printf("(missed) INSB <- 0x%02x\n",R_DX);
451 break;
452 case INSW:
453 R_IP++;
454 printf("(missed) INSW <- 0x%02x\n",R_DX);
455 break;
457 case OUTd:
458 R_IP += 2;
459 port = addr[1];
460 outb(REGS, port);
461 break;
462 case OUTdX:
463 R_IP += 2;
464 port = addr[1];
465 outx(REGS, port);
466 break;
467 case OUT:
468 R_IP++;
469 outb(REGS, R_DX);
470 break;
471 case OUTX:
472 R_IP++;
473 outx(REGS, R_DX);
474 break;
475 case OUTSB:
476 R_IP++;
477 printf("(missed) OUTSB -> 0x%02x\n",R_DX);
478 break;
479 case OUTSW:
480 R_IP++;
481 printf("(missed) OUTSW -> 0x%02x\n",R_DX);
482 /* tmode = 1; */
483 break;
485 case LOCK:
486 debug(D_TRAPS2, "lock\n");
487 R_IP++;
488 break;
490 case HLT: /* BIOS entry points populated with HLT */
491 func = find_callback(MAKEVEC(R_CS, R_IP));
492 if (func) {
493 R_IP++; /* pass HLT opcode */
494 func(REGS);
495 /* dump_regs(REGS); */
496 #if 0
497 update_counter += 5;
498 if (update_counter > BUSY_UPDATES)
499 sigalrm(sf);
500 #endif
501 break;
503 /* if (R_EFLAGS & PSL_VIF) { */
504 R_IP++;
505 tty_pause();
506 goto out;
507 /* } */
508 /* FALLTHRU */
510 default:
511 dump_regs(REGS);
512 fatal("unsupported instruction\n");
515 out:
516 if (tmode)
517 tracetrap(REGS);
519 #endif /* USE_VM86 */
521 void
522 sigtrace(struct sigframe *sf)
524 int x;
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");
529 dump_regs(REGS);
530 for (x = 0; x < 16; ++x)
531 debug(D_ALWAYS, " %02x", *(unsigned char *)x);
532 putc('\n', debugf);
533 } else {
534 debug(D_ALWAYS, "Currently in the emulator\n");
535 sigalrm(sf);
539 void
540 sigtrap(struct sigframe *sf)
542 int intnum;
543 int trapno;
544 regcontext_t *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
546 if ((R_EFLAGS & PSL_VM) == 0) {
547 dump_regs(REGS);
548 fatal("%04x:%08x Sigtrap in protected mode\n", R_CS, R_IP);
551 if (tmode)
552 if (resettrace(REGS))
553 goto doh;
555 #if defined (__FreeBSD__) || defined (__DragonFly__)
556 trapno = (int)sf->sf_siginfo; /* XXX GROSTIC HACK ALERT */
557 #else
558 trapno = sc->sc_trapno;
559 #endif
560 if (trapno == T_BPTFLT)
561 intnum = 3;
562 else
563 intnum = 1;
565 PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
566 PUSH(R_CS, REGS);
567 PUSH(R_IP, REGS);
568 R_FLAGS &= ~PSL_T;
569 PUTVEC(R_CS, R_IP, ivec[intnum]);
571 doh:
572 if (tmode)
573 tracetrap(REGS);
576 void
577 breakpoint(struct sigframe *sf)
579 regcontext_t *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
581 if (R_EFLAGS & PSL_VM)
582 printf("doscmd ");
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");
592 ** periodic updates
594 void
595 sigalrm(struct sigframe *sf)
597 regcontext_t *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
599 if (tmode)
600 resettrace(REGS);
602 update_counter = 0; /* remember we've updated */
603 video_update((regcontext_t *)&REGS->sc);
604 hardint(0x00);
606 if (tmode)
607 tracetrap(REGS);
610 void
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);
616 dump_regs(REGS);
617 fatal("%04x:%04x Illegal instruction\n", R_CS, R_IP);
621 void
622 sigfpe(struct sigframe *sf)
624 regcontext_t *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
626 if (R_EFLAGS & PSL_VM) {
627 dump_regs(REGS);
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? */
631 return;
633 dump_regs(REGS);
634 fatal("%04x:%04x Floating point fault in emulator.\n", R_CS, R_IP);