summaryrefslogtreecommitdiffstats
path: root/usr.bin/doscmd/callback.c
blob: d5ce42804d317d76efcc700f703866e36a742bc3 (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
/* No copyright?! */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <sys/queue.h>
#include "doscmd.h"

/*
** Callbacks are used for chaining interrupt handlers 
** off interrupt vectors
*/

struct callback {
    LIST_ENTRY(callback) chain;
    u_long vec;
    callback_t func;
    const char *name;
};

LIST_HEAD(cbhead , callback) cbhead[127];

#define	CBHASH(x)	(((x) * 17) % 127)

/*
** Register (func) as a handler for (vec)
*/
void
register_callback(u_long vec, callback_t func, const char *name)
{
    struct cbhead *head;
    struct callback *elm;

    elm = malloc(sizeof(struct callback));
    elm->vec = vec;
    elm->func = func;
    elm->name = name;
    
    head = &cbhead[CBHASH(vec)];
    LIST_INSERT_HEAD(head, elm, chain);
}

/*
** Find a handler for (vec)
*/
callback_t
find_callback(u_long vec)
{
    struct cbhead *head;
    struct callback *elm;

    head = &cbhead[CBHASH(vec)];
    LIST_FOREACH(elm, head, chain)
	if (elm->vec == vec)
	    break;
    if (elm) {
	debug(D_TRAPS2, "callback %s\n", elm->name);
	return (elm->func);
    } else
	return ((callback_t)0);
}

u_long trampoline_rover = 0xF1000000;

/*
 * Interrupts are disabled on an INTn call, so we must restore interrupts
 * before via STI returning.  IRET is not used here because 1) some DOS
 * calls want to return status via the FLAGS register, and 2) external
 * routines which hook INTn calls do not always put a FLAGS image on the
 * stack which re-enables interrupts.
 */
u_char softint_trampoline[] = {
    0xf4,	/* HLT */
    0xfb,	/* STI */
    0xca,	/* RETF 2 */
    2,
    0,
};
u_char hardint_trampoline[] = {
    0xf4,	/* HLT */
    0xcf,	/* IRET */
};
u_char null_trampoline[] = {
    0xcf,	/* IRET */
};

u_long
insert_generic_trampoline(size_t len, u_char *p)
{
    u_char *q;
    u_long where;

    where = trampoline_rover;
    q = (u_char *)VECPTR(where);
    memcpy(q, p, len);
    trampoline_rover += len;
    return (where);
}

u_long
insert_softint_trampoline(void)
{
    return (insert_generic_trampoline(
	sizeof(softint_trampoline), softint_trampoline));
}

u_long
insert_hardint_trampoline(void)
{
    return (insert_generic_trampoline(
	sizeof(hardint_trampoline), hardint_trampoline));
}

u_long
insert_null_trampoline(void)
{
    return (insert_generic_trampoline(
	sizeof(null_trampoline), null_trampoline));
}
OpenPOWER on IntegriCloud