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
140
141
142
143
144
|
.global int0
.global int1
.global int2
.global int3
.global int4
.global int5
.global int6
.global int7
.global int8
.global int9
.global int10
.global int11
.global int12
.global int13
.global int14
.global int15
.global int128
//temporary
.global asm_mouse_handler
.global asm_kb_handler
// nothing to ack
.macro ack0
.endm
// ack master
.macro ack1
push %eax // persist
mov $0x20,%al
out %al,$0x20
pop %eax // load original
.endm
// ack master and servant
.macro ack2
push %eax // persist
mov $0x20,%al
out %al,$0xa0 // slave
out %al,$0x20 // master
pop %eax // load original
.endm
// ignore return value
.macro ret0
add $4,%esp
.endm
// put return value in %eax
.macro ret1
pop %eax
.endm
.macro intx ack retx num func
/*
Once we arrived here the stack already contains 3x 32bit values,
which will be poped by 'iret'
- eflags
- return code segment selector
- return instruction pointer
There are two possiblities concerning our stack position:
a) if the interrupt occured while kernel code was executed we are
on the same stack and have no clue about the stack alignment
b) if the interrupt occured while user code was executed the
configured tss.esp0 was used, in this case we are at the start
of the esp0 stack.
*/
\ack //acknowledge interrupt
//also remember that we will get new interrupts only
//after iret or reenabling themn explicitly!
push $0x666 //make room for potential C functions 'return value'.
//we use eax already for esp (so we can context switch)
pusha //Push all standard registers 8 regs x 4bytes/32bit
push %ds //Push data segment
push %es //etc...
push %fs
push %gs
mov %esp,%eax // remember THIS stack position
and $-16,%esp // padding to align stack on 16byte boundary before CALL
sub $8,%esp // ...
push \num // pass in this interrupt number
push %eax // pass in original %esp (saved just few lines before)
call \func
mov %eax,%esp // use the %esp we got from c function
pop %gs // pop everything back...
pop %fs // ...
pop %es
pop %ds
popa
\retx // potentially set return value to eax to return to the caller
iret // pops the return instruction pointer, return code segment selector, and EFLAGS image from the stack
.endm
int0: intx ack1 ret0 $0 interrupt_handler
int1: intx ack1 ret0 $1 interrupt_handler
int2: intx ack1 ret0 $2 interrupt_handler
int3: intx ack1 ret0 $3 interrupt_handler
int4: intx ack1 ret0 $4 interrupt_handler
int5: intx ack1 ret0 $5 interrupt_handler
int6: intx ack1 ret0 $6 interrupt_handler
int7: intx ack1 ret0 $7 interrupt_handler
int8: intx ack2 ret0 $8 interrupt_handler
int9: intx ack2 ret0 $9 interrupt_handler
int10: intx ack2 ret0 $10 interrupt_handler
int11: intx ack2 ret0 $11 interrupt_handler
int12: intx ack2 ret0 $12 interrupt_handler
int13: intx ack2 ret0 $13 interrupt_handler
int14: intx ack2 ret0 $14 interrupt_handler
int15: intx ack2 ret0 $15 interrupt_handler
int128: intx ack0 ret1 $128 interrupt_handler
asm_kb_handler:
push %eax
mov $0x0,%eax
in $0x60,%al
pop %eax
ret
asm_mouse_handler:
push %eax
mov $0x0,%eax
in $0x60,%al
pop %eax
ret
|