2 This contains the installation function for the driver.
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 // Global for the Legacy 8259 Protocol that is produced by this driver
14 EFI_LEGACY_8259_PROTOCOL mInterrupt8259
= {
15 Interrupt8259SetVectorBase
,
19 Interrupt8259GetVector
,
20 Interrupt8259EnableIrq
,
21 Interrupt8259DisableIrq
,
22 Interrupt8259GetInterruptLine
,
23 Interrupt8259EndOfInterrupt
27 // Global for the handle that the Legacy 8259 Protocol is installed
29 EFI_HANDLE m8259Handle
= NULL
;
31 UINT8 mMasterBase
= 0xff;
32 UINT8 mSlaveBase
= 0xff;
33 EFI_8259_MODE mMode
= Efi8259ProtectedMode
;
34 UINT16 mProtectedModeMask
= 0xffff;
35 UINT16 mLegacyModeMask
;
36 UINT16 mProtectedModeEdgeLevel
= 0x0000;
37 UINT16 mLegacyModeEdgeLevel
;
44 Write to mask and edge/level triggered registers of master and slave PICs.
46 @param[in] Mask low byte for master PIC mask register,
47 high byte for slave PIC mask register.
48 @param[in] EdgeLevel low byte for master PIC edge/level triggered register,
49 high byte for slave PIC edge/level triggered register.
53 Interrupt8259WriteMask (
58 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, (UINT8
) Mask
);
59 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, (UINT8
) (Mask
>> 8));
60 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER
, (UINT8
) EdgeLevel
);
61 IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE
, (UINT8
) (EdgeLevel
>> 8));
65 Read from mask and edge/level triggered registers of master and slave PICs.
67 @param[out] Mask low byte for master PIC mask register,
68 high byte for slave PIC mask register.
69 @param[out] EdgeLevel low byte for master PIC edge/level triggered register,
70 high byte for slave PIC edge/level triggered register.
74 Interrupt8259ReadMask (
83 MasterValue
= IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER
);
84 SlaveValue
= IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE
);
86 *Mask
= (UINT16
) (MasterValue
| (SlaveValue
<< 8));
89 if (EdgeLevel
!= NULL
) {
90 MasterValue
= IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER
);
91 SlaveValue
= IoRead8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE
);
93 *EdgeLevel
= (UINT16
) (MasterValue
| (SlaveValue
<< 8));
98 // Legacy 8259 Protocol Interface Functions
102 Sets the base address for the 8259 master and slave PICs.
104 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
105 @param[in] MasterBase Interrupt vectors for IRQ0-IRQ7.
106 @param[in] SlaveBase Interrupt vectors for IRQ8-IRQ15.
108 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
109 @retval EFI_DEVICE_ERROR There was an error while writing to the 8259 PIC.
114 Interrupt8259SetVectorBase (
115 IN EFI_LEGACY_8259_PROTOCOL
*This
,
123 OriginalTpl
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
125 // Set vector base for slave PIC
127 if (SlaveBase
!= mSlaveBase
) {
128 mSlaveBase
= SlaveBase
;
131 // Initialization sequence is needed for setting vector base.
135 // Preserve interrtup mask register before initialization sequence
136 // because it will be cleared during initialization
138 Mask
= IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE
);
141 // ICW1: cascade mode, ICW4 write required
143 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE
, 0x11);
146 // ICW2: new vector base (must be multiple of 8)
148 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, mSlaveBase
);
151 // ICW3: slave indentification code must be 2
153 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, 0x02);
156 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
158 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, 0x01);
161 // Restore interrupt mask register
163 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, Mask
);
167 // Set vector base for master PIC
169 if (MasterBase
!= mMasterBase
) {
170 mMasterBase
= MasterBase
;
173 // Initialization sequence is needed for setting vector base.
177 // Preserve interrtup mask register before initialization sequence
178 // because it will be cleared during initialization
180 Mask
= IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER
);
183 // ICW1: cascade mode, ICW4 write required
185 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER
, 0x11);
188 // ICW2: new vector base (must be multiple of 8)
190 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, mMasterBase
);
193 // ICW3: slave PIC is cascaded on IRQ2
195 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, 0x04);
198 // ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
200 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, 0x01);
203 // Restore interrupt mask register
205 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, Mask
);
208 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE
, LEGACY_8259_EOI
);
209 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER
, LEGACY_8259_EOI
);
211 gBS
->RestoreTPL (OriginalTpl
);
217 Gets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
219 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
220 @param[out] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
221 @param[out] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
222 @param[out] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
223 @param[out] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
225 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
226 @retval EFI_DEVICE_ERROR There was an error while reading the 8259 PIC.
231 Interrupt8259GetMask (
232 IN EFI_LEGACY_8259_PROTOCOL
*This
,
233 OUT UINT16
*LegacyMask
, OPTIONAL
234 OUT UINT16
*LegacyEdgeLevel
, OPTIONAL
235 OUT UINT16
*ProtectedMask
, OPTIONAL
236 OUT UINT16
*ProtectedEdgeLevel OPTIONAL
239 if (LegacyMask
!= NULL
) {
240 *LegacyMask
= mLegacyModeMask
;
243 if (LegacyEdgeLevel
!= NULL
) {
244 *LegacyEdgeLevel
= mLegacyModeEdgeLevel
;
247 if (ProtectedMask
!= NULL
) {
248 *ProtectedMask
= mProtectedModeMask
;
251 if (ProtectedEdgeLevel
!= NULL
) {
252 *ProtectedEdgeLevel
= mProtectedModeEdgeLevel
;
259 Sets the current 16-bit real mode and 32-bit protected-mode IRQ masks.
261 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
262 @param[in] LegacyMask 16-bit mode interrupt mask for IRQ0-IRQ15.
263 @param[in] LegacyEdgeLevel 16-bit mode edge/level mask for IRQ-IRQ15.
264 @param[in] ProtectedMask 32-bit mode interrupt mask for IRQ0-IRQ15.
265 @param[in] ProtectedEdgeLevel 32-bit mode edge/level mask for IRQ0-IRQ15.
267 @retval EFI_SUCCESS The 8259 PIC was programmed successfully.
268 @retval EFI_DEVICE_ERROR There was an error while writing the 8259 PIC.
273 Interrupt8259SetMask (
274 IN EFI_LEGACY_8259_PROTOCOL
*This
,
275 IN UINT16
*LegacyMask
, OPTIONAL
276 IN UINT16
*LegacyEdgeLevel
, OPTIONAL
277 IN UINT16
*ProtectedMask
, OPTIONAL
278 IN UINT16
*ProtectedEdgeLevel OPTIONAL
281 if (LegacyMask
!= NULL
) {
282 mLegacyModeMask
= *LegacyMask
;
285 if (LegacyEdgeLevel
!= NULL
) {
286 mLegacyModeEdgeLevel
= *LegacyEdgeLevel
;
289 if (ProtectedMask
!= NULL
) {
290 mProtectedModeMask
= *ProtectedMask
;
293 if (ProtectedEdgeLevel
!= NULL
) {
294 mProtectedModeEdgeLevel
= *ProtectedEdgeLevel
;
301 Sets the mode of the PICs.
303 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
304 @param[in] Mode 16-bit real or 32-bit protected mode.
305 @param[in] Mask The value with which to set the interrupt mask.
306 @param[in] EdgeLevel The value with which to set the edge/level mask.
308 @retval EFI_SUCCESS The mode was set successfully.
309 @retval EFI_INVALID_PARAMETER The mode was not set.
314 Interrupt8259SetMode (
315 IN EFI_LEGACY_8259_PROTOCOL
*This
,
316 IN EFI_8259_MODE Mode
,
317 IN UINT16
*Mask
, OPTIONAL
318 IN UINT16
*EdgeLevel OPTIONAL
325 if (Mode
== Efi8259LegacyMode
) {
327 // In Efi8259ProtectedMode, mask and edge/level trigger registers should
328 // be changed through this protocol, so we can track them in the
329 // corresponding module variables.
331 Interrupt8259ReadMask (&mProtectedModeMask
, &mProtectedModeEdgeLevel
);
335 // Update the Mask for the new mode
337 mLegacyModeMask
= *Mask
;
340 if (EdgeLevel
!= NULL
) {
342 // Update the Edge/Level triggered mask for the new mode
344 mLegacyModeEdgeLevel
= *EdgeLevel
;
350 // Write new legacy mode mask/trigger level
352 Interrupt8259WriteMask (mLegacyModeMask
, mLegacyModeEdgeLevel
);
357 if (Mode
== Efi8259ProtectedMode
) {
359 // Save the legacy mode mask/trigger level
361 Interrupt8259ReadMask (&mLegacyModeMask
, &mLegacyModeEdgeLevel
);
363 // Always force Timer to be enabled after return from 16-bit code.
364 // This always insures that on next entry, timer is counting.
366 mLegacyModeMask
&= 0xFFFE;
370 // Update the Mask for the new mode
372 mProtectedModeMask
= *Mask
;
375 if (EdgeLevel
!= NULL
) {
377 // Update the Edge/Level triggered mask for the new mode
379 mProtectedModeEdgeLevel
= *EdgeLevel
;
385 // Write new protected mode mask/trigger level
387 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
392 return EFI_INVALID_PARAMETER
;
396 Translates the IRQ into a vector.
398 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
399 @param[in] Irq IRQ0-IRQ15.
400 @param[out] Vector The vector that is assigned to the IRQ.
402 @retval EFI_SUCCESS The Vector that matches Irq was returned.
403 @retval EFI_INVALID_PARAMETER Irq is not valid.
408 Interrupt8259GetVector (
409 IN EFI_LEGACY_8259_PROTOCOL
*This
,
414 if ((UINT32
)Irq
> Efi8259Irq15
) {
415 return EFI_INVALID_PARAMETER
;
418 if (Irq
<= Efi8259Irq7
) {
419 *Vector
= (UINT8
) (mMasterBase
+ Irq
);
421 *Vector
= (UINT8
) (mSlaveBase
+ (Irq
- Efi8259Irq8
));
428 Enables the specified IRQ.
430 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
431 @param[in] Irq IRQ0-IRQ15.
432 @param[in] LevelTriggered 0 = Edge triggered; 1 = Level triggered.
434 @retval EFI_SUCCESS The Irq was enabled on the 8259 PIC.
435 @retval EFI_INVALID_PARAMETER The Irq is not valid.
440 Interrupt8259EnableIrq (
441 IN EFI_LEGACY_8259_PROTOCOL
*This
,
443 IN BOOLEAN LevelTriggered
446 if ((UINT32
)Irq
> Efi8259Irq15
) {
447 return EFI_INVALID_PARAMETER
;
450 mProtectedModeMask
= (UINT16
) (mProtectedModeMask
& ~(1 << Irq
));
451 if (LevelTriggered
) {
452 mProtectedModeEdgeLevel
= (UINT16
) (mProtectedModeEdgeLevel
| (1 << Irq
));
454 mProtectedModeEdgeLevel
= (UINT16
) (mProtectedModeEdgeLevel
& ~(1 << Irq
));
457 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
463 Disables the specified IRQ.
465 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
466 @param[in] Irq IRQ0-IRQ15.
468 @retval EFI_SUCCESS The Irq was disabled on the 8259 PIC.
469 @retval EFI_INVALID_PARAMETER The Irq is not valid.
474 Interrupt8259DisableIrq (
475 IN EFI_LEGACY_8259_PROTOCOL
*This
,
479 if ((UINT32
)Irq
> Efi8259Irq15
) {
480 return EFI_INVALID_PARAMETER
;
483 mProtectedModeMask
= (UINT16
) (mProtectedModeMask
| (1 << Irq
));
485 mProtectedModeEdgeLevel
= (UINT16
) (mProtectedModeEdgeLevel
& ~(1 << Irq
));
487 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
493 Reads the PCI configuration space to get the interrupt number that is assigned to the card.
495 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
496 @param[in] PciHandle PCI function for which to return the vector.
497 @param[out] Vector IRQ number that corresponds to the interrupt line.
499 @retval EFI_SUCCESS The interrupt line value was read successfully.
504 Interrupt8259GetInterruptLine (
505 IN EFI_LEGACY_8259_PROTOCOL
*This
,
506 IN EFI_HANDLE PciHandle
,
510 EFI_PCI_IO_PROTOCOL
*PciIo
;
514 Status
= gBS
->HandleProtocol (
516 &gEfiPciIoProtocolGuid
,
519 if (EFI_ERROR (Status
)) {
520 return EFI_INVALID_PARAMETER
;
531 // Interrupt line is same location for standard PCI cards, standard
532 // bridge and CardBus bridge.
534 *Vector
= InterruptLine
;
540 Issues the End of Interrupt (EOI) commands to PICs.
542 @param[in] This Indicates the EFI_LEGACY_8259_PROTOCOL instance.
543 @param[in] Irq The interrupt for which to issue the EOI command.
545 @retval EFI_SUCCESS The EOI command was issued.
546 @retval EFI_INVALID_PARAMETER The Irq is not valid.
551 Interrupt8259EndOfInterrupt (
552 IN EFI_LEGACY_8259_PROTOCOL
*This
,
556 if ((UINT32
)Irq
> Efi8259Irq15
) {
557 return EFI_INVALID_PARAMETER
;
560 if (Irq
>= Efi8259Irq8
) {
561 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE
, LEGACY_8259_EOI
);
564 IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER
, LEGACY_8259_EOI
);
572 @param[in] ImageHandle ImageHandle of the loaded driver.
573 @param[in] SystemTable Pointer to the EFI System Table.
575 @retval EFI_SUCCESS One or more of the drivers returned a success code.
576 @retval !EFI_SUCCESS Error installing Legacy 8259 Protocol.
582 IN EFI_HANDLE ImageHandle
,
583 IN EFI_SYSTEM_TABLE
*SystemTable
590 // Initialze mask values from PCDs
592 mLegacyModeMask
= PcdGet16 (Pcd8259LegacyModeMask
);
593 mLegacyModeEdgeLevel
= PcdGet16 (Pcd8259LegacyModeEdgeLevel
);
596 // Clear all pending interrupt
598 for (Irq
= Efi8259Irq0
; Irq
<= Efi8259Irq15
; Irq
++) {
599 Interrupt8259EndOfInterrupt (&mInterrupt8259
, Irq
);
603 // Set the 8259 Master base to 0x68 and the 8259 Slave base to 0x70
605 Status
= Interrupt8259SetVectorBase (&mInterrupt8259
, PROTECTED_MODE_BASE_VECTOR_MASTER
, PROTECTED_MODE_BASE_VECTOR_SLAVE
);
608 // Set all 8259 interrupts to edge triggered and disabled
610 Interrupt8259WriteMask (mProtectedModeMask
, mProtectedModeEdgeLevel
);
613 // Install 8259 Protocol onto a new handle
615 Status
= gBS
->InstallProtocolInterface (
617 &gEfiLegacy8259ProtocolGuid
,
618 EFI_NATIVE_INTERFACE
,