aboutsummaryrefslogtreecommitdiffstats
path: root/intr.h
blob: 3a5c8625e9db4c48639f4cf253979c121245348d (plain) (blame)
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/* -*- Mode: C; c-basic-offset: 3 -*-
 *
 * intr.h - Interrupt vector management and interrupt routing.
 *
 * This file is part of Metalkit, a simple collection of modules for
 * writing software that runs on the bare metal. Get the latest code
 * at http://svn.navi.cx/misc/trunk/metalkit/
 *
 * Copyright (c) 2008-2009 Micah Dowty
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef __INTR_H__
#define __INTR_H__

#include "types.h"
#include "io.h"

#define NUM_INTR_VECTORS    256
#define NUM_FAULT_VECTORS   0x20
#define NUM_IRQ_VECTORS     0x10
#define IRQ_VECTOR_BASE     NUM_FAULT_VECTORS
#define IRQ_VECTOR(irq)     ((irq) + IRQ_VECTOR_BASE)
#define USER_VECTOR_BASE    (IRQ_VECTOR_BASE + NUM_IRQ_VECTORS)
#define USER_VECTOR(n)      ((n) + USER_VECTOR_BASE)

#define IRQ_TIMER           0
#define IRQ_KEYBOARD        1

#define FAULT_DE            0x00    // Divide error
#define FAULT_NMI           0x02    // Non-maskable interrupt
#define FAULT_BP            0x03    // Breakpoint
#define FAULT_OF            0x04    // Overflow
#define FAULT_BR            0x05    // Bound range
#define FAULT_UD            0x06    // Undefined opcode
#define FAULT_NM            0x07    // No FPU
#define FAULT_DF            0x08    // Double Fault
#define FAULT_TS            0x0A    // Invalid TSS
#define FAULT_NP            0x0B    // Segment not present
#define FAULT_SS            0x0C    // Stack-segment fault
#define FAULT_GP            0x0D    // General Protection Fault
#define FAULT_PF            0x0E    // Page fault
#define FAULT_MF            0x10    // Math fault
#define FAULT_AC            0x11    // Alignment check
#define FAULT_MC            0x12    // Machine check
#define FAULT_XM            0x13    // SIMD floating point exception

#define PIC1_COMMAND_PORT  0x20
#define PIC1_DATA_PORT     0x21
#define PIC2_COMMAND_PORT  0xA0
#define PIC2_DATA_PORT     0xA1

typedef void (*IntrHandler)(int vector);
typedef void (*IntrContextFn)(void);

fastcall void Intr_Init(void);
fastcall void Intr_SetFaultHandlers(IntrHandler handler);

static inline void
Intr_Enable(void) {
   asm volatile ("sti");
}

static inline void
Intr_Disable(void) {
   asm volatile ("cli");
}

static inline Bool
Intr_Save(void) {
   uint32 eflags;
   asm volatile ("pushf; pop %0" : "=r" (eflags));
   return (eflags & 0x200) != 0;
}

static inline void
Intr_Restore(Bool flag) {
   if (flag) {
      Intr_Enable();
   } else {
      Intr_Disable();
   }
}

static inline void
Intr_Halt(void) {
   asm volatile ("hlt");
}

static inline void
Intr_Break(void) {
   asm volatile ("int3");
}

/*
 * This structure describes all execution state that's saved when an
 * interrupt or a setjmp occurs. In the case of an interrupt, this
 * structure actually describes the stack frame of the interrupt
 * trampoline.
 *
 * An interrupt handler can get a pointer to its IntrContext by
 * passing its first argument to the Intr_GetContext macro. This
 * allows an interrupt handler to examine the execution context in
 * which the interrupt occurred, to modify the interrupt's return
 * address, or even to implement input and output for OS traps.
 *
 * This module also provides functions for directly saving and
 * restoring IntrContext structures. This can be used much like
 * setjmp/longjmp, or it can even be used for simple cooperative or
 * preemptive multithreading. An interrupt handler can perform a
 * context switch by overwriting its IntrContext with a saved context.
 *
 * The definition of this structure must be kept in sync with the
 * machine code in our interrupt trampolines, and with the
 * assembly-language implementation of SaveContext and RestoreContext.
 */

typedef struct IntrContext {
   /*
    * General purpose registers. These are all saved after the value
    * of %esp is captured.
    */

   uint32  edi;
   uint32  esi;
   uint32  ebp;
   uint32  esp;
   uint32  ebx;
   uint32  edx;
   uint32  ecx;
   uint32  eax;

   /*
    * These values are save by the CPU during an interrupt.  By
    * convention, these values are at the top of the stack when %esp
    * was saved.
    *
    * The values of cs and eflags are ignored by Intr_SaveContext
    * and Intr_RestoreContext.
    */

   uint32  eip;
   uint32  cs;
   uint32  eflags;
} IntrContext;

/*
 * Always use the 'volatile' keyword when storing the result
 * of Intr_GetContext. GCC can erroneously decide to optimize
 * out any copies to this pointer, because it doesn't know the
 * values will be used by our trampoline.
 */

#define Intr_GetContext(arg)  ((IntrContext*) &(&arg)[1])

uint32 Intr_SaveContext(IntrContext *ctx);
void Intr_RestoreContext(IntrContext *ctx);
fastcall void Intr_InitContext(IntrContext *ctx, uint32 *stack, IntrContextFn main);

/*
 * To save space, we don't include assembly-language trampolines for
 * each interrupt vector. Instead, we allocate a table in the BSS
 * segment which we can fill in at runtime with simple trampoline
 * functions. This structure actually describes executable 32-bit
 * code.
 */

typedef struct {
   uint16      code1;
   uint32      arg;
   uint8       code2;
   IntrHandler handler;
   uint32      code3;
   uint32      code4;
   uint32      code5;
   uint32      code6;
   uint32      code7;
   uint32      code8;
} PACKED IntrTrampolineType;

extern IntrTrampolineType ALIGNED(4) IntrTrampoline[NUM_INTR_VECTORS];

/*
 * Intr_SetHandler --
 *
 *    Set a C-language interrupt handler for a particular vector.
 *    Note that the argument is a vector number, not an IRQ.
 */

static inline void
Intr_SetHandler(int vector, IntrHandler handler)
{
   IntrTrampoline[vector].handler = handler;
}

/*
 * Intr_SetMask --
 *
 *    (Un)mask a particular IRQ.
 */

static inline void
Intr_SetMask(int irq, Bool enable)
{
   uint8 port, bit, mask;

   if (irq >= 8) {
      bit = 1 << (irq - 8);
      port = PIC2_DATA_PORT;
   } else {
      bit = 1 << irq;
      port = PIC1_DATA_PORT;
   }

   mask = IO_In8(port);

   /* A '1' bit in the mask inhibits the interrupt. */
   if (enable) {
      mask &= ~bit;
   } else {
      mask |= bit;
   }

   IO_Out8(port, mask);
}


#endif /* __INTR_H__ */