kernel: Use hashdestroy() to free hash tables allocated with hashinit().
[dragonfly.git] / usr.bin / doscmd / trap.c
1 /*
2  * Copyright (c) 1992, 1993, 1996
3  *      Berkeley Software Design, Inc.  All rights reserved.
4  *
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.
17  *
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.
29  *
30  *      BSDI trap.c,v 2.3 1996/04/08 19:33:08 bostic Exp
31  *
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 $
34  */
35
36 #include <machine/trap.h>
37
38 #include "doscmd.h"
39 #include "trap.h"
40 #include "tty.h"
41 #include "video.h"
42
43 /* 
44 ** When the emulator is very busy, it's often common for
45 ** SIGALRM to be missed, leading to missed screen updates.
46 **
47 ** We update this counter every time a DOS interrupt is processed and
48 ** if it hits a certain threshold, force an update.
49 **
50 ** When updates occur, the counter is zeroed.
51 */
52 static int      update_counter = 0;
53 #define         BUSY_UPDATES    2000
54
55 /*
56 ** handle interrupts passed to us by the kernel
57 */
58 void
59 fake_int(regcontext_t *REGS, int intnum)
60 {
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);
76         }
77         return;
78     }
79
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);
85
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];
92
93         R_CS = 0x2c7; 
94         R_IP = 0x14f9;
95         addr = (char *)MAKEPTR(R_CS, R_IP);
96
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;
106         }
107         exit (0);
108 #else
109         tmode = 1;
110 #endif
111     }
112 #endif
113
114     if (intnum == 0)
115         dump_regs(REGS);
116
117     if (ivec[intnum] == 0) {            /* uninitialised interrupt? */
118         if (vflag) dump_regs(REGS);
119         fatal("Call to uninitialised interrupt 0x%02x\n", intnum);
120     }
121
122     /*
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.
127      */
128     if (intnum == 0x21 && R_AX == 0x3E)
129         reset_poll();
130
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]);
137 }
138
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 */
141
142 #ifdef USE_VM86
143 /* entry from NetBSD-style vm86 */
144 void
145 sigurg(struct sigframe *sf)
146 {
147 #define sc      (&sf->sf_sc)
148     int intnum;
149     u_char *addr;
150     int rep;
151     int port;
152     callback_t func;
153
154 #if 0
155     printf("ivec08 = %08x\n", ivec[0x08]);
156 #endif
157
158     if (tmode)
159         resettrace(sc);
160
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;
172                 }
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;
179                 }
180                 break;
181             }
182             break;
183         }
184         fake_int(sc, intnum);
185         break;
186     case VM86_UNKNOWN:
187         /*XXXXX failed vector also gets here without IP adjust*/
188
189         addr = (u_char *)MAKEPTR(sc->sc_cs, sc->sc_eip);
190         rep = 1;
191
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;
266             }
267         default:
268             dump_regs(sc);
269             fatal("unsupported instruction\n");
270         }
271                 break;
272         default:
273                 dump_regs(sc);
274                 printf("code = %04x\n", sf->sf_code);
275                 fatal("unrecognized vm86 trap\n");
276         }
277
278 out:
279         if (tmode)
280                 tracetrap(sc);
281 #undef  sc
282 #undef  ipadvance
283 }
284
285 #else /* USE_VM86 */
286
287 /* entry from FreeBSD, BSD/OS vm86 */
288 void
289 sigbus(struct sigframe *sf)
290 {
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);
297
298     if (!(R_EFLAGS & PSL_VM))
299         fatal("SIGBUS in the emulator\n");
300
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 */
316         }
317     }
318
319     addr = (u_char *)MAKEPTR(R_CS, R_IP);
320
321     if (tmode)
322         resettrace(REGS);
323
324     if ((R_EFLAGS & (PSL_VIP | PSL_VIF)) == (PSL_VIP | PSL_VIF)) {
325         resume_interrupt();
326         goto out;
327     }
328     
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);
340         }
341         printf("Trapno, error: %p %p\n", REGS->sc.sc_trapno, REGS->sc.sc_err);
342         fflush(stdout);
343         dump_regs(REGS);
344     }
345 #endif
346     
347         switch (addr[0]) {              /* what was that again dear? */
348
349         case CLI:
350             debug (D_TRAPS2, "cli\n");
351             R_IP++;
352             R_EFLAGS &= ~PSL_VIP;
353             break;
354
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;
364             
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;
371
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 */
377
378         case POPF:
379 /* XXX */
380             fatal("popf/iret in emulator");
381
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));
392
393             /* restore pseudo PSL_I flag */
394             IntState = tempflags & PSL_I;
395             debug(D_TRAPS2, "popf -> 0x%lx\n", R_EFLAGS);
396             break;
397
398         case TRACETRAP:
399             debug(D_TRAPS2, "ttrap\n");
400             R_IP++;
401             fake_int(REGS, 3);
402             break;
403
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;
415                     }
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;
422                     }
423                     break;
424                 }
425                 break;
426             }
427             fake_int(REGS, intnum);
428             break;
429
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;
456
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;
484
485         case LOCK:
486             debug(D_TRAPS2, "lock\n");
487             R_IP++;
488             break;
489
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;
502             }
503 /*            if (R_EFLAGS & PSL_VIF) { */
504                 R_IP++;
505                 tty_pause();
506                 goto out;
507 /*            } */
508             /* FALLTHRU */
509
510         default:
511             dump_regs(REGS);
512             fatal("unsupported instruction\n");
513         }
514
515 out:
516         if (tmode)
517             tracetrap(REGS);        
518 }
519 #endif /* USE_VM86 */
520
521 void
522 sigtrace(struct sigframe *sf)
523 {
524     int                 x;
525     regcontext_t        *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
526
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);
536     }
537 }
538
539 void
540 sigtrap(struct sigframe *sf)
541 {   
542     int                 intnum;
543     int                 trapno;
544     regcontext_t        *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
545
546     if ((R_EFLAGS & PSL_VM) == 0) {
547         dump_regs(REGS);
548         fatal("%04x:%08x Sigtrap in protected mode\n", R_CS, R_IP);
549     }
550
551     if (tmode)
552         if (resettrace(REGS))
553             goto doh;
554
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;
564
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]);
570
571 doh:
572     if (tmode)
573         tracetrap(REGS);
574 }
575
576 void
577 breakpoint(struct sigframe *sf)
578 {
579     regcontext_t        *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
580
581     if (R_EFLAGS & PSL_VM)
582         printf("doscmd ");
583     printf("breakpoint: %04x\n", *(u_short *)0x8e64);
584
585     __asm__ volatile("mov 0, %eax");
586     __asm__ volatile(".byte 0x0f");             /* MOV DR6,EAX */
587     __asm__ volatile(".byte 0x21");
588     __asm__ volatile(".byte 0x1b");
589 }
590
591 /*
592 ** periodic updates
593 */
594 void
595 sigalrm(struct sigframe *sf)
596 {
597     regcontext_t        *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
598
599     if (tmode)
600         resettrace(REGS);
601
602     update_counter = 0;                 /* remember we've updated */
603     video_update((regcontext_t *)&REGS->sc);
604     hardint(0x00);
605
606     if (tmode)
607         tracetrap(REGS);
608 }
609
610 void
611 sigill(struct sigframe *sf)
612 {
613     regcontext_t        *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
614
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);
618
619 }
620
621 void
622 sigfpe(struct sigframe *sf)
623 {
624     regcontext_t        *REGS = (regcontext_t *)(&sf->sf_uc.uc_mcontext);
625
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;
632     }
633     dump_regs(REGS);
634     fatal("%04x:%04x Floating point fault in emulator.\n", R_CS, R_IP);
635 }