浏览代码

Ripped out everything except the ability to send EOI to the PIC.

tags/v0.9.3
Michael Brown 18 年前
父节点
当前提交
b12cd68726
共有 2 个文件被更改,包括 71 次插入360 次删除
  1. 37
    299
      src/arch/i386/core/pic8259.c
  2. 34
    61
      src/arch/i386/include/pic8259.h

+ 37
- 299
src/arch/i386/core/pic8259.c 查看文件

@@ -1,263 +1,37 @@
1 1
 /*
2
- * Basic support for controlling the 8259 Programmable Interrupt Controllers.
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3 3
  *
4
- * Initially written by Michael Brown (mcb30).
5
- */
6
-
7
-#include <etherboot.h>
8
-#include "pic8259.h"
9
-#include "old_realmode.h"
10
-
11
-/* State of trivial IRQ handler */
12
-irq_t trivial_irq_installed_on = IRQ_NONE;
13
-static uint16_t trivial_irq_previous_trigger_count = 0;
14
-
15
-/* The actual trivial IRQ handler
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
16 8
  *
17
- * Note: we depend on the C compiler not realising that we're putting
18
- * variables in the ".text16" section and therefore not forcing them
19
- * back to the ".data" section.  I don't see any reason to expect this
20
- * behaviour to change.
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
21 13
  *
22
- * These must *not* be the first variables to appear in this file; the
23
- * first variable to appear gets the ".data" directive.
24
- */
25
-RM_FRAGMENT(_trivial_irq_handler,
26
-	"pushw %bx\n\t"
27
-	"call  1f\n1:\tpopw %bx\n\t"   /* PIC access to variables */
28
-	"incw  %cs:(_trivial_irq_trigger_count-1b)(%bx)\n\t" 
29
-	"popw  %bx\n\t" 
30
-	"iret\n\t" 
31
-	"\n\t"
32
-	".globl _trivial_irq_trigger_count\n\t"
33
-	"_trivial_irq_trigger_count: .short 0\n\t"
34
-	"\n\t"
35
-	".globl _trivial_irq_chain_to\n\t"
36
-	"_trivial_irq_chain_to: .short 0,0\n\t"
37
-	"\n\t"
38
-	".globl _trivial_irq_chain\n\t"
39
-	"_trivial_irq_chain: .byte 0\n\t"
40
-	);
41
-extern volatile uint16_t _trivial_irq_trigger_count;
42
-extern segoff_t _trivial_irq_chain_to;
43
-extern int8_t _trivial_irq_chain;
44
-
45
-/* Current locations of trivial IRQ handler.  These will change at
46
- * runtime when relocation is used; the handler needs to be copied to
47
- * base memory before being installed.
48
- */
49
-void (*trivial_irq_handler)P((void)) = _trivial_irq_handler;
50
-uint16_t volatile *trivial_irq_trigger_count = &_trivial_irq_trigger_count;
51
-segoff_t *trivial_irq_chain_to = &_trivial_irq_chain_to;
52
-uint8_t *trivial_irq_chain = &_trivial_irq_chain;
53
-
54
-/* Install a handler for the specified IRQ.  Address of previous
55
- * handler will be stored in previous_handler.  Enabled/disabled state
56
- * of IRQ will be preserved across call, therefore if the handler does
57
- * chaining, ensure that either (a) IRQ is disabled before call, or
58
- * (b) previous_handler points directly to the place that the handler
59
- * picks up its chain-to address.
60
- */
61
-
62
-int install_irq_handler ( irq_t irq, segoff_t *handler,
63
-			  uint8_t *previously_enabled,
64
-			  segoff_t *previous_handler ) {
65
-	segoff_t *irq_vector = IRQ_VECTOR ( irq );
66
-	*previously_enabled = irq_enabled ( irq );
67
-
68
-	if ( irq > IRQ_MAX ) {
69
-		DBG ( "Invalid IRQ number %d\n" );
70
-		return 0;
71
-	}
72
-
73
-	previous_handler->segment = irq_vector->segment;
74
-	previous_handler->offset = irq_vector->offset;
75
-	if ( *previously_enabled ) disable_irq ( irq );
76
-	DBG ( "Installing handler at %hx:%hx for IRQ %d (vector 0000:%hx),"
77
-	      " leaving %s\n",
78
-	      handler->segment, handler->offset, irq, virt_to_phys(irq_vector),
79
-	      ( *previously_enabled ? "enabled" : "disabled" ) );
80
-	DBG ( "...(previous handler at %hx:%hx)\n",
81
-	      previous_handler->segment, previous_handler->offset );
82
-	irq_vector->segment = handler->segment;
83
-	irq_vector->offset = handler->offset;
84
-	if ( *previously_enabled ) enable_irq ( irq );
85
-	return 1;
86
-}
87
-
88
-/* Remove handler for the specified IRQ.  Routine checks that another
89
- * handler has not been installed that chains to handler before
90
- * uninstalling handler.  Enabled/disabled state of the IRQ will be
91
- * restored to that specified by previously_enabled.
92
- */
93
-
94
-int remove_irq_handler ( irq_t irq, segoff_t *handler,
95
-			 uint8_t *previously_enabled,
96
-			 segoff_t *previous_handler ) {
97
-	segoff_t *irq_vector = IRQ_VECTOR ( irq );
98
-
99
-	if ( irq > IRQ_MAX ) {
100
-		DBG ( "Invalid IRQ number %d\n" );
101
-		return 0;
102
-	}
103
-	if ( ( irq_vector->segment != handler->segment ) ||
104
-	     ( irq_vector->offset != handler->offset ) ) {
105
-		DBG ( "Cannot remove handler for IRQ %d\n" );
106
-		return 0;
107
-	}
108
-
109
-	DBG ( "Removing handler for IRQ %d\n", irq );
110
-	disable_irq ( irq );
111
-	irq_vector->segment = previous_handler->segment;
112
-	irq_vector->offset = previous_handler->offset;
113
-	if ( *previously_enabled ) enable_irq ( irq );
114
-	return 1;
115
-}
116
-
117
-/* Install the trivial IRQ handler.  This routine installs the
118
- * handler, tests it and enables the IRQ.
119
- */
120
-
121
-int install_trivial_irq_handler ( irq_t irq ) {
122
-	segoff_t trivial_irq_handler_segoff = SEGOFF(trivial_irq_handler);
123
-	
124
-	if ( trivial_irq_installed_on != IRQ_NONE ) {
125
-		DBG ( "Can install trivial IRQ handler only once\n" );
126
-		return 0;
127
-	}
128
-	if ( SEGMENT(trivial_irq_handler) > 0xffff ) {
129
-		DBG ( "Trivial IRQ handler not in base memory\n" );
130
-		return 0;
131
-	}
132
-
133
-	DBG ( "Installing trivial IRQ handler on IRQ %d\n", irq );
134
-	if ( ! install_irq_handler ( irq, &trivial_irq_handler_segoff,
135
-				     trivial_irq_chain,
136
-				     trivial_irq_chain_to ) )
137
-		return 0;
138
-	trivial_irq_installed_on = irq;
139
-
140
-	DBG ( "Testing trivial IRQ handler\n" );
141
-	disable_irq ( irq );
142
-	*trivial_irq_trigger_count = 0;
143
-	trivial_irq_previous_trigger_count = 0;
144
-	fake_irq ( irq );
145
-	if ( ! trivial_irq_triggered ( irq ) ) {
146
-		DBG ( "Installation of trivial IRQ handler failed\n" );
147
-		remove_trivial_irq_handler ( irq );
148
-		return 0;
149
-	}
150
-	/* Send EOI just in case there was a leftover interrupt */
151
-	send_specific_eoi ( irq );
152
-	DBG ( "Trivial IRQ handler installed successfully\n" );
153
-	enable_irq ( irq );
154
-	return 1;
155
-}
156
-
157
-/* Remove the trivial IRQ handler.
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
158 17
  */
159 18
 
160
-int remove_trivial_irq_handler ( irq_t irq ) {
161
-	segoff_t trivial_irq_handler_segoff = SEGOFF(trivial_irq_handler);
162
-
163
-	if ( trivial_irq_installed_on == IRQ_NONE ) return 1;
164
-	if ( irq != trivial_irq_installed_on ) {
165
-		DBG ( "Cannot uninstall trivial IRQ handler from IRQ %d; "
166
-		      "is installed on IRQ %d\n", irq,
167
-		      trivial_irq_installed_on );
168
-		return 0;
169
-	}
170
-
171
-	if ( ! remove_irq_handler ( irq, &trivial_irq_handler_segoff,
172
-				    trivial_irq_chain,
173
-				    trivial_irq_chain_to ) )
174
-		return 0;
19
+#include <pic8259.h>
175 20
 
176
-	if ( trivial_irq_triggered ( trivial_irq_installed_on ) ) {
177
-		DBG ( "Sending EOI for unwanted trivial IRQ\n" );
178
-		send_specific_eoi ( trivial_irq_installed_on );
179
-	}
180
-
181
-	trivial_irq_installed_on = IRQ_NONE;
182
-	return 1;
183
-}
184
-
185
-/* Safe method to detect whether or not trivial IRQ has been
186
- * triggered.  Using this call avoids potential race conditions.  This
187
- * call will return success only once per trigger.
188
- */
189
-
190
-int trivial_irq_triggered ( irq_t irq ) {
191
-	uint16_t trivial_irq_this_trigger_count = *trivial_irq_trigger_count;
192
-	int triggered = ( trivial_irq_this_trigger_count -
193
-			  trivial_irq_previous_trigger_count );
194
-	
195
-	/* irq is not used at present, but we have it in the API for
196
-	 * future-proofing; in case we want the facility to have
197
-	 * multiple trivial IRQ handlers installed simultaneously.
198
-	 *
199
-	 * Avoid compiler warning about unused variable.
200
-	 */
201
-	if ( irq == IRQ_NONE ) {};
202
-	
203
-	trivial_irq_previous_trigger_count = trivial_irq_this_trigger_count;
204
-	return triggered ? 1 : 0;
205
-}
206
-
207
-/* Copy trivial IRQ handler to a new location.  Typically used to copy
208
- * the handler into base memory; when relocation is being used we need
209
- * to do this before installing the handler.
21
+/** @file
22
+ *
23
+ * Minimal support for the 8259 Programmable Interrupt Controller
210 24
  *
211
- * Call with target=NULL in order to restore the handler to its
212
- * original location.
213 25
  */
214 26
 
215
-int copy_trivial_irq_handler ( void *target, size_t target_size ) {
216
-	irq_t currently_installed_on = trivial_irq_installed_on;
217
-	uint32_t offset = ( target == NULL ? 0 :
218
-			    target - (void*)_trivial_irq_handler );
219
-
220
-	if (( target != NULL ) && ( target_size < TRIVIAL_IRQ_HANDLER_SIZE )) {
221
-		DBG ( "Insufficient space to copy trivial IRQ handler\n" );
222
-		return 0;
223
-	}
224
-
225
-	if ( currently_installed_on != IRQ_NONE ) {
226
-		DBG ("WARNING: relocating trivial IRQ handler while in use\n");
227
-		if ( ! remove_trivial_irq_handler ( currently_installed_on ) )
228
-			return 0;
229
-	}
230
-
231
-	/* Do the actual copy */
232
-	if ( target != NULL ) {
233
-		DBG ( "Copying trivial IRQ handler to %hx:%hx\n",
234
-		      SEGMENT(target), OFFSET(target) );
235
-		memcpy ( target, _trivial_irq_handler,
236
-			 TRIVIAL_IRQ_HANDLER_SIZE );
237
-	} else {
238
-		DBG ( "Restoring trivial IRQ handler to original location\n" );
239
-	}
240
-	/* Update all the pointers to structures within the handler */
241
-	trivial_irq_handler = ( void (*)P((void)) )
242
-		( (void*)_trivial_irq_handler + offset );
243
-	trivial_irq_trigger_count = (uint16_t*)
244
-		( (void*)&_trivial_irq_trigger_count + offset );
245
-	trivial_irq_chain_to = (segoff_t*)
246
-		( (void*)&_trivial_irq_chain_to + offset );
247
-	trivial_irq_chain = (uint8_t*)
248
-		( (void*)&_trivial_irq_chain + offset );
249
-
250
-	if ( currently_installed_on != IRQ_NONE ) {
251
-		if ( ! install_trivial_irq_handler ( currently_installed_on ) )
252
-			return 0;
253
-	}
254
-	return 1;
255
-}
256
-
257
-/* Send non-specific EOI(s).  This seems to be inherently unsafe.
27
+/**
28
+ * Send non-specific EOI(s)
29
+ *
30
+ * @v irq		IRQ number
31
+ *
32
+ * This seems to be inherently unsafe.
258 33
  */
259
-
260
-void send_nonspecific_eoi ( irq_t irq ) {
34
+static inline void send_nonspecific_eoi ( unsigned int irq ) {
261 35
 	DBG ( "Sending non-specific EOI for IRQ %d\n", irq );
262 36
 	if ( irq >= IRQ_PIC_CUTOFF ) {
263 37
 		outb ( ICR_EOI_NON_SPECIFIC, PIC2_ICR );
@@ -265,61 +39,25 @@ void send_nonspecific_eoi ( irq_t irq ) {
265 39
 	outb ( ICR_EOI_NON_SPECIFIC, PIC1_ICR );
266 40
 }
267 41
 
268
-/* Send specific EOI(s).
42
+/**
43
+ * Send specific EOI(s)
44
+ *
45
+ * @v irq		IRQ number
269 46
  */
270
-
271
-void send_specific_eoi ( irq_t irq ) {
47
+static inline void send_specific_eoi ( unsigned int irq ) {
272 48
 	DBG ( "Sending specific EOI for IRQ %d\n", irq );
273
-	outb ( ICR_EOI_SPECIFIC | ICR_VALUE(irq), ICR_REG(irq) );
49
+	outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( irq ) ), ICR_REG ( irq ) );
274 50
 	if ( irq >= IRQ_PIC_CUTOFF ) {
275
-		outb ( ICR_EOI_SPECIFIC | ICR_VALUE(CHAINED_IRQ),
276
-		       ICR_REG(CHAINED_IRQ) );
51
+		outb ( ( ICR_EOI_SPECIFIC | ICR_VALUE ( CHAINED_IRQ ) ),
52
+		       ICR_REG ( CHAINED_IRQ ) );
277 53
 	}
278 54
 }
279 55
 
280
-/* Fake an IRQ
281
- */
282
-
283
-void fake_irq ( irq_t irq ) {
284
-	struct {
285
-		uint16_t int_number;
286
-	} PACKED in_stack;
287
-
288
-	/* Convert IRQ to INT number:
289
-	 *
290
-	 * subb	$0x08,%cl	Invert bit 3, set bits 4-7 iff irq < 8
291
-	 * xorb	$0x70,%cl	Invert bits 4-6
292
-	 * andb	$0x7f,%cl	Clear bit 7
293
-	 *
294
-	 * No, it's not the most intuitive method, but I was proud to
295
-	 * get it down to three lines of assembler when this routine
296
-	 * was originally implemented in pcbios.S.
297
-	 */
298
-	in_stack.int_number = ( ( irq - 8 ) ^ 0x70 ) & 0x7f;
299
-
300
-	RM_FRAGMENT(rm_fake_irq,
301
-		"popw %ax\n\t"		/* %ax = INT number */
302
-		"call 1f\n1:\tpop %bx\n\t"
303
-		"movb %al, %cs:(2f-1b+1)(%bx)\n\t" /* Overwrite INT number..*/
304
-		"\n2:\tint $0x00\n\t"		    /* ..in this instruction */
305
-	);
306
-
307
-	real_call ( rm_fake_irq, &in_stack, NULL );
308
-}
309
-
310
-/* Dump current 8259 status: enabled IRQs and handler addresses.
56
+/**
57
+ * Send End-Of-Interrupt to the PIC
58
+ *
59
+ * @v irq		IRQ number
311 60
  */
312
-
313
-#ifdef DEBUG_IRQ
314
-void dump_irq_status ( void ) {
315
-	int irq = 0;
316
-	
317
-	for ( irq = 0; irq < 16; irq++ ) {
318
-		if ( irq_enabled ( irq ) ) {
319
-			printf ( "IRQ%d enabled, ISR at %hx:%hx\n", irq,
320
-				 IRQ_VECTOR(irq)->segment,
321
-				 IRQ_VECTOR(irq)->offset );
322
-		}
323
-	}
61
+void send_eoi ( unsigned int irq ) {
62
+	send_specific_eoi ( irq );
324 63
 }
325
-#endif

+ 34
- 61
src/arch/i386/include/pic8259.h 查看文件

@@ -10,38 +10,38 @@
10 10
 /* For segoff_t */
11 11
 #include "realmode.h"
12 12
 
13
-#define IRQ_PIC_CUTOFF (8)
13
+#define IRQ_PIC_CUTOFF 8
14 14
 
15 15
 /* 8259 register locations */
16
-#define PIC1_ICW1 (0x20)
17
-#define PIC1_OCW2 (0x20)
18
-#define PIC1_OCW3 (0x20)
19
-#define PIC1_ICR (0x20)
20
-#define PIC1_IRR (0x20)
21
-#define PIC1_ISR (0x20)
22
-#define PIC1_ICW2 (0x21)
23
-#define PIC1_ICW3 (0x21)
24
-#define PIC1_ICW4 (0x21)
25
-#define PIC1_IMR (0x21)
26
-#define PIC2_ICW1 (0xa0)
27
-#define PIC2_OCW2 (0xa0)
28
-#define PIC2_OCW3 (0xa0)
29
-#define PIC2_ICR (0xa0)
30
-#define PIC2_IRR (0xa0)
31
-#define PIC2_ISR (0xa0)
32
-#define PIC2_ICW2 (0xa1)
33
-#define PIC2_ICW3 (0xa1)
34
-#define PIC2_ICW4 (0xa1)
35
-#define PIC2_IMR (0xa1)
16
+#define PIC1_ICW1 0x20
17
+#define PIC1_OCW2 0x20
18
+#define PIC1_OCW3 0x20
19
+#define PIC1_ICR 0x20
20
+#define PIC1_IRR 0x20
21
+#define PIC1_ISR 0x20
22
+#define PIC1_ICW2 0x21
23
+#define PIC1_ICW3 0x21
24
+#define PIC1_ICW4 0x21
25
+#define PIC1_IMR 0x21
26
+#define PIC2_ICW1 0xa0
27
+#define PIC2_OCW2 0xa0
28
+#define PIC2_OCW3 0xa0
29
+#define PIC2_ICR 0xa0
30
+#define PIC2_IRR 0xa0
31
+#define PIC2_ISR 0xa0
32
+#define PIC2_ICW2 0xa1
33
+#define PIC2_ICW3 0xa1
34
+#define PIC2_ICW4 0xa1
35
+#define PIC2_IMR 0xa1
36 36
 
37 37
 /* Register command values */
38
-#define OCW3_ID (0x08)
39
-#define OCW3_READ_IRR (0x03)
40
-#define OCW3_READ_ISR (0x02)
41
-#define ICR_EOI_NON_SPECIFIC (0x20)
42
-#define ICR_EOI_NOP (0x40)
43
-#define ICR_EOI_SPECIFIC (0x60)
44
-#define ICR_EOI_SET_PRIORITY (0xc0)
38
+#define OCW3_ID 0x08
39
+#define OCW3_READ_IRR 0x03
40
+#define OCW3_READ_ISR 0x02
41
+#define ICR_EOI_NON_SPECIFIC 0x20
42
+#define ICR_EOI_NOP 0x40
43
+#define ICR_EOI_SPECIFIC 0x60
44
+#define ICR_EOI_SET_PRIORITY 0xc0
45 45
 
46 46
 /* Macros to enable/disable IRQs */
47 47
 #define IMR_REG(x) ( (x) < IRQ_PIC_CUTOFF ? PIC1_IMR : PIC2_IMR )
@@ -51,46 +51,19 @@
51 51
 #define disable_irq(x) outb ( inb( IMR_REG(x) ) | IMR_BIT(x), IMR_REG(x) )
52 52
 
53 53
 /* Macros for acknowledging IRQs */
54
-#define ICR_REG(x) ( (x) < IRQ_PIC_CUTOFF ? PIC1_ICR : PIC2_ICR )
55
-#define ICR_VALUE(x) ( (x) % IRQ_PIC_CUTOFF )
54
+#define ICR_REG( irq ) ( (irq) < IRQ_PIC_CUTOFF ? PIC1_ICR : PIC2_ICR )
55
+#define ICR_VALUE( irq ) ( (irq) % IRQ_PIC_CUTOFF )
56 56
 #define CHAINED_IRQ 2
57 57
 
58 58
 /* Utility macros to convert IRQ numbers to INT numbers and INT vectors  */
59
-#define IRQ_INT(x) ( (x)<IRQ_PIC_CUTOFF ? (x)+0x08 : (x)-IRQ_PIC_CUTOFF+0x70 )
60
-#define INT_VECTOR(x) ( (segoff_t*) phys_to_virt( 4 * (x) ) )
61
-#define IRQ_VECTOR(x) ( INT_VECTOR ( IRQ_INT(x) ) )
59
+#define IRQ_INT( irq ) ( ( ( (irq) - IRQ_PIC_CUTOFF ) ^ 0x70 ) & 0x7f )
62 60
 
63 61
 /* Other constants */
64
-typedef uint8_t irq_t;
65
-#define IRQ_MAX (15)
66
-#define IRQ_NONE (0xff)
62
+#define IRQ_MAX 15
63
+#define IRQ_NONE -1U
67 64
 
68 65
 /* Function prototypes
69 66
  */
70
-int install_irq_handler ( irq_t irq, segoff_t *handler,
71
-			  uint8_t *previously_enabled,
72
-			  segoff_t *previous_handler );
73
-int remove_irq_handler ( irq_t irq, segoff_t *handler,
74
-			 uint8_t *previously_enabled,
75
-			 segoff_t *previous_handler );
76
-int install_trivial_irq_handler ( irq_t irq );
77
-int remove_trivial_irq_handler ( irq_t irq );
78
-int trivial_irq_triggered ( irq_t irq );
79
-int copy_trivial_irq_handler ( void *target, size_t target_size );
80
-void send_non_specific_eoi ( irq_t irq );
81
-void send_specific_eoi ( irq_t irq );
82
-void fake_irq ( irq_t irq );
83
-#ifdef DEBUG_IRQ
84
-void dump_irq_status ( void );
85
-#else
86
-#define dump_irq_status()
87
-#endif
88
-
89
-/* Other code (e.g. undi.c) needs to know the size of the trivial IRQ
90
- * handler code, so we put prototypes and the size macro here.
91
- */
92
-extern void _trivial_irq_handler ( void );
93
-extern char _trivial_irq_handler_size[];
94
-#define TRIVIAL_IRQ_HANDLER_SIZE FRAGMENT_SIZE(_trivial_irq_handler)
67
+void send_eoi ( unsigned int irq );
95 68
 
96 69
 #endif /* PIC8259_H */

正在加载...
取消
保存