summaryrefslogtreecommitdiffstats
path: root/usr.bin/doscmd/int.c
blob: 7657d219654bcfecbac403e24d11234151a02427 (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
/*
** No copyright?!
**
** $FreeBSD$
*/
#include "doscmd.h"

/*
** Cause a software interrupt to happen immediately after we
** return to vm86 mode
*/
void
softint(int intnum)
{
    regcontext_t	*REGS = saved_regcontext;
    u_long vec = ivec[intnum];

    /*
    ** if we're dead, or there's no vector or the saved registers are
    ** invalid
    */
    if (dead || !saved_valid || vec == 0)
	return;

    /* 
    ** if the vector points into the BIOS, or the handler at the other
    ** end is just an IRET, don't bother.
    */
    if ((vec >> 16) == 0xf000 || *(u_char *)VECPTR(vec) == 0xcf)
	return;

#if 0
    /*
     * software interrupts are always taken
     */
    if ((R_EFLAGS & PSL_VIF) == 0) {
        delay_interrupt(intnum, softint);
        return;
    }
#endif

    debug(D_TRAPS|intnum, "Int%x [%04x:%04x]\n", 
	  intnum, vec >> 16, vec & 0xffff);

    PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
    PUSH(R_CS, REGS);
    PUSH(R_IP, REGS);
#if 1
    R_EFLAGS &= ~PSL_VIF;		/* XXX disable interrupts? */
#else
    R_EFLAGS |= PSL_VIF;
#endif
    PUTVEC(R_CS, R_IP, vec);
}

/*
** Cause a hardware interrupt to happen immediately after
** we return to vm86 mode
*/
void
hardint(int intnum)
{
    regcontext_t	*REGS = saved_regcontext;
    u_long vec = ivec[intnum];

    /*
     * XXXXX
     * We should simulate the IRQ mask in the PIC.
     */
	
	/* 
	** if we're dead, or there's no vector, or the saved registers
	** are invalid
	*/
	if (dead || !saved_valid || vec == 0)
	    return;
	
	/* 
	** if the vector points into the BIOS, or the handler at the
	** other end is just an IRET, don't bother 
	*/
	if ((vec >> 16) == 0xf000 || *(u_char *)VECPTR(vec) == 0xcf)
	    return;

     if ((R_EFLAGS & PSL_VIF) == 0) {
         delay_interrupt(intnum, hardint);
         return;
     }
	
	debug(D_TRAPS|intnum, "Int%x [%04x:%04x]\n",
	      intnum, vec >> 16, vec & 0xffff);

        PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
	PUSH(R_CS, REGS);
	PUSH(R_IP, REGS);
#if 1
	R_EFLAGS &= ~PSL_VIF;		/* XXX disable interrupts */
#else
        R_EFLAGS |= PSL_VIF;
#endif
	PUTVEC(R_CS, R_IP, vec);
}

typedef void (*foo_t)(int);

void
resume_interrupt(void)
{
    int i;
    regcontext_t      *REGS = saved_regcontext;

    n_pending--;
    if (n_pending == 0)
        R_EFLAGS &= ~PSL_VIP;
    
    for (i = 0; i < 256; i++) {
        if (pending[i]) {
            ((foo_t)(pending[i]))(i);
            pending[i] = 0;
            break;    
        }
    }
}   
     
     
void 
delay_interrupt(int intnum, void (*func)(int))
{       
    regcontext_t      *REGS = saved_regcontext;

#if 0
printf("DELAY [%x/%d]\n", intnum, n_pending);
#endif
    if (pending[intnum] == 0) {
        pending[intnum] = (u_long)func;
        n_pending++;
    }
    R_EFLAGS |= PSL_VIP;
}   
OpenPOWER on IntegriCloud