VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/PcAtChipsetPkg/8259InterruptControllerDxe/8259.c@ 62180

最後變更 在這個檔案從62180是 58466,由 vboxsync 提交於 9 年 前

EFI/Firmware: Merged in the svn:eol-style, svn:mime-type and trailing whitespace cleanup that was done after the initial UDK2014.SP1 import: svn merge /vendor/edk2/UDK2014.SP1 /vendor/edk2/current .

  • 屬性 svn:eol-style 設為 native
檔案大小: 16.5 KB
 
1/** @file
2 This contains the installation function for the driver.
3
4Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "8259.h"
16
17//
18// Global for the Legacy 8259 Protocol that is produced by this driver
19//
20EFI_LEGACY_8259_PROTOCOL mInterrupt8259 = {
21 Interrupt8259SetVectorBase,
22 Interrupt8259GetMask,
23 Interrupt8259SetMask,
24 Interrupt8259SetMode,
25 Interrupt8259GetVector,
26 Interrupt8259EnableIrq,
27 Interrupt8259DisableIrq,
28 Interrupt8259GetInterruptLine,
29 Interrupt8259EndOfInterrupt
30};
31
32//
33// Global for the handle that the Legacy 8259 Protocol is installed
34//
35EFI_HANDLE m8259Handle = NULL;
36
37UINT8 mMasterBase = 0xff;
38UINT8 mSlaveBase = 0xff;
39EFI_8259_MODE mMode = Efi8259ProtectedMode;
40UINT16 mProtectedModeMask = 0xffff;
41UINT16 mLegacyModeMask;
42UINT16 mProtectedModeEdgeLevel = 0x0000;
43UINT16 mLegacyModeEdgeLevel;
44
45//
46// Worker Functions
47//
48
49/**
50 Write to mask and edge/level triggered registers of master and slave PICs.
51
52 @param[in] Mask low byte for master PIC mask register,
53 high byte for slave PIC mask register.
54 @param[in] EdgeLevel low byte for master PIC edge/level triggered register,
55 high byte for slave PIC edge/level triggered register.
56
57**/
58VOID
59Interrupt8259WriteMask (
60 IN UINT16 Mask,
61 IN UINT16 EdgeLevel
62 )
63{
64 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, (UINT8) Mask);
65 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, (UINT8) (Mask >> 8));
66 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER, (UINT8) EdgeLevel);
67 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE, (UINT8) (EdgeLevel >> 8));
68}
69
70/**
71 Read from mask and edge/level triggered registers of master and slave PICs.
72
73 @param[out] Mask low byte for master PIC mask register,
74 high byte for slave PIC mask register.
75 @param[out] EdgeLevel low byte for master PIC edge/level triggered register,
76 high byte for slave PIC edge/level triggered register.
77
78**/
79VOID
80Interrupt8259ReadMask (
81 OUT UINT16 *Mask,
82 OUT UINT16 *EdgeLevel
83 )
84{
85 UINT16 MasterValue;
86 UINT16 SlaveValue;
87
88 if (Mask != NULL) {
89 MasterValue = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
90 SlaveValue = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
91
92 *Mask = (UINT16) (MasterValue | (SlaveValue << 8));
93 }
94
95 if (EdgeLevel != NULL) {
96 MasterValue = IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER);
97 SlaveValue = IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE);
98
99 *EdgeLevel = (UINT16) (MasterValue | (SlaveValue << 8));
100 }
101}
102
103//
104// Legacy 8259 Protocol Interface Functions
105//
106
107/**
108 Sets the base address for the 8259 master and slave PICs.
109
110 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
111 @param[in] MasterBase Interrupt vectors for IRQ0-IRQ7.
112 @param[in] SlaveBase Interrupt vectors for IRQ8-IRQ15.
113
114 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
115 @retval EFI_DEVICE_ERROR There was an error while writing to the 8259 PIC.
116
117**/
118EFI_STATUS
119EFIAPI
120Interrupt8259SetVectorBase (
121 IN EFI_LEGACY_8259_PROTOCOL *This,
122 IN UINT8 MasterBase,
123 IN UINT8 SlaveBase
124 )
125{
126 UINT8 Mask;
127 EFI_TPL OriginalTpl;
128
129 OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
130 //
131 // Set vector base for slave PIC
132 //
133 if (SlaveBase != mSlaveBase) {
134 mSlaveBase = SlaveBase;
135
136 //
137 // Initialization sequence is needed for setting vector base.
138 //
139
140 //
141 // Preserve interrtup mask register before initialization sequence
142 // because it will be cleared during intialization
143 //
144 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
145
146 //
147 // ICW1: cascade mode, ICW4 write required
148 //
149 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x11);
150
151 //
152 // ICW2: new vector base (must be multiple of 8)
153 //
154 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, mSlaveBase);
155
156 //
157 // ICW3: slave indentification code must be 2
158 //
159 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x02);
160
161 //
162 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
163 //
164 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x01);
165
166 //
167 // Restore interrupt mask register
168 //
169 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, Mask);
170 }
171
172 //
173 // Set vector base for master PIC
174 //
175 if (MasterBase != mMasterBase) {
176 mMasterBase = MasterBase;
177
178 //
179 // Initialization sequence is needed for setting vector base.
180 //
181
182 //
183 // Preserve interrtup mask register before initialization sequence
184 // because it will be cleared during intialization
185 //
186 Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
187
188 //
189 // ICW1: cascade mode, ICW4 write required
190 //
191 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x11);
192
193 //
194 // ICW2: new vector base (must be multiple of 8)
195 //
196 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, mMasterBase);
197
198 //
199 // ICW3: slave PIC is cascaded on IRQ2
200 //
201 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x04);
202
203 //
204 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
205 //
206 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x01);
207
208 //
209 // Restore interrupt mask register
210 //
211 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, Mask);
212 }
213
214 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);
215 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);
216
217 gBS->RestoreTPL (OriginalTpl);
218
219 return EFI_SUCCESS;
220}
221
222/**
223 Gets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
224
225 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
226 @param[out] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
227 @param[out] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
228 @param[out] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
229 @param[out] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
230
231 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
232 @retval EFI_DEVICE_ERROR There was an error while reading the 8259 PIC.
233
234**/
235EFI_STATUS
236EFIAPI
237Interrupt8259GetMask (
238 IN EFI_LEGACY_8259_PROTOCOL *This,
239 OUT UINT16 *LegacyMask, OPTIONAL
240 OUT UINT16 *LegacyEdgeLevel, OPTIONAL
241 OUT UINT16 *ProtectedMask, OPTIONAL
242 OUT UINT16 *ProtectedEdgeLevel OPTIONAL
243 )
244{
245 if (LegacyMask != NULL) {
246 *LegacyMask = mLegacyModeMask;
247 }
248
249 if (LegacyEdgeLevel != NULL) {
250 *LegacyEdgeLevel = mLegacyModeEdgeLevel;
251 }
252
253 if (ProtectedMask != NULL) {
254 *ProtectedMask = mProtectedModeMask;
255 }
256
257 if (ProtectedEdgeLevel != NULL) {
258 *ProtectedEdgeLevel = mProtectedModeEdgeLevel;
259 }
260
261 return EFI_SUCCESS;
262}
263
264/**
265 Sets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
266
267 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
268 @param[in] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
269 @param[in] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
270 @param[in] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
271 @param[in] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
272
273 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
274 @retval EFI_DEVICE_ERROR There was an error while writing the 8259 PIC.
275
276**/
277EFI_STATUS
278EFIAPI
279Interrupt8259SetMask (
280 IN EFI_LEGACY_8259_PROTOCOL *This,
281 IN UINT16 *LegacyMask, OPTIONAL
282 IN UINT16 *LegacyEdgeLevel, OPTIONAL
283 IN UINT16 *ProtectedMask, OPTIONAL
284 IN UINT16 *ProtectedEdgeLevel OPTIONAL
285 )
286{
287 if (LegacyMask != NULL) {
288 mLegacyModeMask = *LegacyMask;
289 }
290
291 if (LegacyEdgeLevel != NULL) {
292 mLegacyModeEdgeLevel = *LegacyEdgeLevel;
293 }
294
295 if (ProtectedMask != NULL) {
296 mProtectedModeMask = *ProtectedMask;
297 }
298
299 if (ProtectedEdgeLevel != NULL) {
300 mProtectedModeEdgeLevel = *ProtectedEdgeLevel;
301 }
302
303 return EFI_SUCCESS;
304}
305
306/**
307 Sets the mode of the PICs.
308
309 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
310 @param[in] Mode 16-bit real or 32-bit protected mode.
311 @param[in] Mask The value with which to set the interrupt mask.
312 @param[in] EdgeLevel The value with which to set the edge/level mask.
313
314 @retval EFI_SUCCESS The mode was set successfully.
315 @retval EFI_INVALID_PARAMETER The mode was not set.
316
317**/
318EFI_STATUS
319EFIAPI
320Interrupt8259SetMode (
321 IN EFI_LEGACY_8259_PROTOCOL *This,
322 IN EFI_8259_MODE Mode,
323 IN UINT16 *Mask, OPTIONAL
324 IN UINT16 *EdgeLevel OPTIONAL
325 )
326{
327 if (Mode == mMode) {
328 return EFI_SUCCESS;
329 }
330
331 if (Mode == Efi8259LegacyMode) {
332 //
333 // In Efi8259ProtectedMode, mask and edge/level trigger registers should
334 // be changed through this protocol, so we can track them in the
335 // corresponding module variables.
336 //
337 Interrupt8259ReadMask (&mProtectedModeMask, &mProtectedModeEdgeLevel);
338
339 if (Mask != NULL) {
340 //
341 // Update the Mask for the new mode
342 //
343 mLegacyModeMask = *Mask;
344 }
345
346 if (EdgeLevel != NULL) {
347 //
348 // Update the Edge/Level triggered mask for the new mode
349 //
350 mLegacyModeEdgeLevel = *EdgeLevel;
351 }
352
353 mMode = Mode;
354
355 //
356 // Write new legacy mode mask/trigger level
357 //
358 Interrupt8259WriteMask (mLegacyModeMask, mLegacyModeEdgeLevel);
359
360 return EFI_SUCCESS;
361 }
362
363 if (Mode == Efi8259ProtectedMode) {
364 //
365 // Save the legacy mode mask/trigger level
366 //
367 Interrupt8259ReadMask (&mLegacyModeMask, &mLegacyModeEdgeLevel);
368 //
369 // Always force Timer to be enabled after return from 16-bit code.
370 // This always insures that on next entry, timer is counting.
371 //
372 mLegacyModeMask &= 0xFFFE;
373
374 if (Mask != NULL) {
375 //
376 // Update the Mask for the new mode
377 //
378 mProtectedModeMask = *Mask;
379 }
380
381 if (EdgeLevel != NULL) {
382 //
383 // Update the Edge/Level triggered mask for the new mode
384 //
385 mProtectedModeEdgeLevel = *EdgeLevel;
386 }
387
388 mMode = Mode;
389
390 //
391 // Write new protected mode mask/trigger level
392 //
393 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
394
395 return EFI_SUCCESS;
396 }
397
398 return EFI_INVALID_PARAMETER;
399}
400
401/**
402 Translates the IRQ into a vector.
403
404 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
405 @param[in] Irq IRQ0-IRQ15.
406 @param[out] Vector The vector that is assigned to the IRQ.
407
408 @retval EFI_SUCCESS The Vector that matches Irq was returned.
409 @retval EFI_INVALID_PARAMETER Irq is not valid.
410
411**/
412EFI_STATUS
413EFIAPI
414Interrupt8259GetVector (
415 IN EFI_LEGACY_8259_PROTOCOL *This,
416 IN EFI_8259_IRQ Irq,
417 OUT UINT8 *Vector
418 )
419{
420 if ((UINT32)Irq > Efi8259Irq15) {
421 return EFI_INVALID_PARAMETER;
422 }
423
424 if (Irq <= Efi8259Irq7) {
425 *Vector = (UINT8) (mMasterBase + Irq);
426 } else {
427 *Vector = (UINT8) (mSlaveBase + (Irq - Efi8259Irq8));
428 }
429
430 return EFI_SUCCESS;
431}
432
433/**
434 Enables the specified IRQ.
435
436 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
437 @param[in] Irq IRQ0-IRQ15.
438 @param[in] LevelTriggered 0 = Edge triggered; 1 = Level triggered.
439
440 @retval EFI_SUCCESS The Irq was enabled on the 8259 PIC.
441 @retval EFI_INVALID_PARAMETER The Irq is not valid.
442
443**/
444EFI_STATUS
445EFIAPI
446Interrupt8259EnableIrq (
447 IN EFI_LEGACY_8259_PROTOCOL *This,
448 IN EFI_8259_IRQ Irq,
449 IN BOOLEAN LevelTriggered
450 )
451{
452 if ((UINT32)Irq > Efi8259Irq15) {
453 return EFI_INVALID_PARAMETER;
454 }
455
456 mProtectedModeMask = (UINT16) (mProtectedModeMask & ~(1 << Irq));
457 if (LevelTriggered) {
458 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel | (1 << Irq));
459 } else {
460 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
461 }
462
463 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
464
465 return EFI_SUCCESS;
466}
467
468/**
469 Disables the specified IRQ.
470
471 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
472 @param[in] Irq IRQ0-IRQ15.
473
474 @retval EFI_SUCCESS The Irq was disabled on the 8259 PIC.
475 @retval EFI_INVALID_PARAMETER The Irq is not valid.
476
477**/
478EFI_STATUS
479EFIAPI
480Interrupt8259DisableIrq (
481 IN EFI_LEGACY_8259_PROTOCOL *This,
482 IN EFI_8259_IRQ Irq
483 )
484{
485 if ((UINT32)Irq > Efi8259Irq15) {
486 return EFI_INVALID_PARAMETER;
487 }
488
489 mProtectedModeMask = (UINT16) (mProtectedModeMask | (1 << Irq));
490
491 mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
492
493 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
494
495 return EFI_SUCCESS;
496}
497
498/**
499 Reads the PCI configuration space to get the interrupt number that is assigned to the card.
500
501 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
502 @param[in] PciHandle PCI function for which to return the vector.
503 @param[out] Vector IRQ number that corresponds to the interrupt line.
504
505 @retval EFI_SUCCESS The interrupt line value was read successfully.
506
507**/
508EFI_STATUS
509EFIAPI
510Interrupt8259GetInterruptLine (
511 IN EFI_LEGACY_8259_PROTOCOL *This,
512 IN EFI_HANDLE PciHandle,
513 OUT UINT8 *Vector
514 )
515{
516 EFI_PCI_IO_PROTOCOL *PciIo;
517 UINT8 InterruptLine;
518 EFI_STATUS Status;
519
520 Status = gBS->HandleProtocol (
521 PciHandle,
522 &gEfiPciIoProtocolGuid,
523 (VOID **) &PciIo
524 );
525 if (EFI_ERROR (Status)) {
526 return EFI_INVALID_PARAMETER;
527 }
528
529 PciIo->Pci.Read (
530 PciIo,
531 EfiPciIoWidthUint8,
532 PCI_INT_LINE_OFFSET,
533 1,
534 &InterruptLine
535 );
536 //
537 // Interrupt line is same location for standard PCI cards, standard
538 // bridge and CardBus bridge.
539 //
540 *Vector = InterruptLine;
541
542 return EFI_SUCCESS;
543}
544
545/**
546 Issues the End of Interrupt (EOI) commands to PICs.
547
548 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
549 @param[in] Irq The interrupt for which to issue the EOI command.
550
551 @retval EFI_SUCCESS The EOI command was issued.
552 @retval EFI_INVALID_PARAMETER The Irq is not valid.
553
554**/
555EFI_STATUS
556EFIAPI
557Interrupt8259EndOfInterrupt (
558 IN EFI_LEGACY_8259_PROTOCOL *This,
559 IN EFI_8259_IRQ Irq
560 )
561{
562 if ((UINT32)Irq > Efi8259Irq15) {
563 return EFI_INVALID_PARAMETER;
564 }
565
566 if (Irq >= Efi8259Irq8) {
567 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);
568 }
569
570 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);
571
572 return EFI_SUCCESS;
573}
574
575/**
576 Driver Entry point.
577
578 @param[in] ImageHandle ImageHandle of the loaded driver.
579 @param[in] SystemTable Pointer to the EFI System Table.
580
581 @retval EFI_SUCCESS One or more of the drivers returned a success code.
582 @retval !EFI_SUCCESS Error installing Legacy 8259 Protocol.
583
584**/
585EFI_STATUS
586EFIAPI
587Install8259 (
588 IN EFI_HANDLE ImageHandle,
589 IN EFI_SYSTEM_TABLE *SystemTable
590 )
591{
592 EFI_STATUS Status;
593 EFI_8259_IRQ Irq;
594
595 //
596 // Initialze mask values from PCDs
597 //
598 mLegacyModeMask = PcdGet16 (Pcd8259LegacyModeMask);
599 mLegacyModeEdgeLevel = PcdGet16 (Pcd8259LegacyModeEdgeLevel);
600
601 //
602 // Clear all pending interrupt
603 //
604 for (Irq = Efi8259Irq0; Irq <= Efi8259Irq15; Irq++) {
605 Interrupt8259EndOfInterrupt (&mInterrupt8259, Irq);
606 }
607
608 //
609 // Set the 8259 Master base to 0x68 and the 8259 Slave base to 0x70
610 //
611 Status = Interrupt8259SetVectorBase (&mInterrupt8259, PROTECTED_MODE_BASE_VECTOR_MASTER, PROTECTED_MODE_BASE_VECTOR_SLAVE);
612
613 //
614 // Set all 8259 interrupts to edge triggered and disabled
615 //
616 Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
617
618 //
619 // Install 8259 Protocol onto a new handle
620 //
621 Status = gBS->InstallProtocolInterface (
622 &m8259Handle,
623 &gEfiLegacy8259ProtocolGuid,
624 EFI_NATIVE_INTERFACE,
625 &mInterrupt8259
626 );
627 return Status;
628}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette