-
Notifications
You must be signed in to change notification settings - Fork 3
/
ints.h
114 lines (95 loc) · 3.05 KB
/
ints.h
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
#include <dos.h>
#define ISR_STACK_SIZE 4096
/* SwitchStack() should be called at the start of an ISR function to swap
* out the stack pointer to point to the isr_stack_space memory block.
*
* When an interrupt is serviced, CS and DS are restored so that all our
* pointers work as expected, but unless we do something, SS:SP still points
* to the calling program's stack. This means that pointers to data on the
* stack do not resolve correctly, since DS != SS. While it is possible to
* carefully avoid taking pointers to anything on the stack, it tends to be
* fragile and error-prone, with confusing bugs that are hard to track
* down. isr_stack_space is located in our data segment so we can set
* SS = DS while the interrupt is being serviced.
*
* After switching to the new stack we push the old SS, SP and BP register
* values; RestoreStack() will pop them off and restore the old stack.
*/
#if defined(__TURBOC__)
#define RESTORE_ISR_STACK \
do { \
asm pop bp; \
asm pop cx; \
asm pop bx; \
asm mov ss, bx; \
asm mov sp, cx; \
} while(0)
#define SWITCH_ISR_STACK \
do { \
unsigned int nsp = \
(FP_OFF(isr_stack_space + sizeof(isr_stack_space) - 32)); \
asm mov ax, nsp; \
asm mov bx, ss; \
asm mov cx, sp; \
asm mov dx, ds; \
asm mov ss, dx; \
asm mov sp, ax; \
asm push bx; \
asm push cx; \
asm push bp; \
asm mov bp, sp; \
} while(0)
#elif defined(__WATCOMC__)
extern void SwitchStack(unsigned int);
#pragma aux SwitchStack = \
"mov bx, ss" \
"mov cx, sp" \
"mov dx, ds" \
"mov ss, dx" \
"mov sp, ax" \
"push bx" \
"push cx" \
"push bp" \
"mov bp, sp" \
parm [ax] \
modify [bx cx dx];
extern void RestoreStack(void);
#pragma aux RestoreStack = \
"pop bp" \
"pop cx" \
"pop bx" \
"mov ss, bx" \
"mov sp, cx" \
modify [bx cx];
extern unsigned int old_stacklow;
extern unsigned int _STACKLOW; // Watcom-internal
// For Watcom we must override the _STACKLOW variable to point to the bottom
// of the new stack, in order to play nice with Watcom's stack overflow
// detection code that gets included in function headers.
#define SWITCH_ISR_STACK \
do { \
SwitchStack(FP_OFF(isr_stack_space + sizeof(isr_stack_space) - 32)); \
old_stacklow = _STACKLOW; \
_STACKLOW = FP_OFF(isr_stack_space); \
} while(0)
#define RESTORE_ISR_STACK \
do { \
RestoreStack(); \
_STACKLOW = old_stacklow; \
} while(0)
#else
#error No stack switching implemented for this compiler!
#endif
typedef void (interrupt far *interrupt_handler_t)();
struct interrupt_hook
{
int force_vector;
int interrupt_num;
interrupt_handler_t old_isr;
};
int FindAndHookInterrupt(struct interrupt_hook *state,
interrupt_handler_t isr);
void RestoreInterrupt(struct interrupt_hook *state);
unsigned int SwitchPSP(void);
void RestorePSP(unsigned int old_psp);
extern unsigned char isr_stack_space[ISR_STACK_SIZE];