480 lines
14 KiB
C
480 lines
14 KiB
C
/** @file
|
|
8259 PEIM initialize.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2015, Insyde Software Corporation. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
#include <8259.h>
|
|
|
|
//
|
|
// Global Value
|
|
//
|
|
UINT8 mMasterBase = 0xff;
|
|
UINT8 mSlaveBase = 0xff;
|
|
UINT16 mProtectedModeMask = 0xffff;
|
|
UINT16 mProtectedModeEdgeLevel = 0x0000;
|
|
|
|
//
|
|
// Global for the Legacy 8259 PPI that is produced by this module
|
|
//
|
|
H2O_LEGACY_8259_PPI mInterrupt8259 = {
|
|
Interrupt8259SetVectorBase,
|
|
Interrupt8259GetMask,
|
|
Interrupt8259SetMask,
|
|
Interrupt8259SetMode,
|
|
Interrupt8259GetVector,
|
|
Interrupt8259EnableIrq,
|
|
Interrupt8259DisableIrq,
|
|
Interrupt8259GetInterruptLine,
|
|
Interrupt8259EndOfInterrupt
|
|
};
|
|
|
|
EFI_PEI_PPI_DESCRIPTOR mPpiList = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gH2OLegacy8259PpiGuid,
|
|
&mInterrupt8259
|
|
};
|
|
|
|
//
|
|
// Worker Functions
|
|
//
|
|
|
|
/**
|
|
Write to mask and edge/level triggered registers of master and slave PICs.
|
|
|
|
@param[in] Mask low byte for master PIC mask register,
|
|
high byte for slave PIC mask register.
|
|
@param[in] EdgeLevel low byte for master PIC edge/level triggered register,
|
|
high byte for slave PIC edge/level triggered register.
|
|
|
|
**/
|
|
VOID
|
|
Interrupt8259WriteMask (
|
|
IN UINT16 Mask,
|
|
IN UINT16 EdgeLevel
|
|
)
|
|
{
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, (UINT8) Mask);
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, (UINT8) (Mask >> 8));
|
|
IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_MASTER, (UINT8) EdgeLevel);
|
|
IoWrite8 (LEGACY_8259_EDGE_LEVEL_TRIGGERED_REGISTER_SLAVE, (UINT8) (EdgeLevel >> 8));
|
|
}
|
|
|
|
//
|
|
// Legacy 8259 PPI Interface Functions
|
|
//
|
|
|
|
/**
|
|
Get the 8259 interrupt masks for Irq0 - Irq15. A different mask exists for
|
|
the legacy mode mask and the protected mode mask. The base address for the 8259
|
|
is different for legacy and protected mode, so two masks are required.
|
|
|
|
@param[in] This The PPI instance pointer.
|
|
@param[in] MasterBase The base vector for the Master PIC in the 8259 controller.
|
|
@param[in] SlaveBase The base vector for the Slave PIC in the 8259 controller.
|
|
|
|
@retval EFI_SUCCESS The new bases were programmed.
|
|
@retval EFI_DEVICE_ERROR A device error occured programming the vector bases.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Interrupt8259SetVectorBase (
|
|
IN H2O_LEGACY_8259_PPI *This,
|
|
IN UINT8 MasterBase,
|
|
IN UINT8 SlaveBase
|
|
)
|
|
{
|
|
UINT8 Mask;
|
|
|
|
//
|
|
// Set vector base for slave PIC
|
|
//
|
|
if (SlaveBase != mSlaveBase) {
|
|
mSlaveBase = SlaveBase;
|
|
|
|
//
|
|
// Initialization sequence is needed for setting vector base.
|
|
//
|
|
|
|
//
|
|
// Preserve interrtup mask register before initialization sequence
|
|
// because it will be cleared during intialization
|
|
//
|
|
Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_SLAVE);
|
|
|
|
//
|
|
// ICW1: cascade mode, ICW4 write required
|
|
//
|
|
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, 0x11);
|
|
|
|
//
|
|
// ICW2: new vector base (must be multiple of 8)
|
|
//
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, mSlaveBase);
|
|
|
|
//
|
|
// ICW3: slave indentification code must be 2
|
|
//
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x02);
|
|
|
|
//
|
|
// ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
|
|
//
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0x01);
|
|
|
|
//
|
|
// Restore interrupt mask register
|
|
//
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, Mask);
|
|
}
|
|
|
|
//
|
|
// Set vector base for master PIC
|
|
//
|
|
if (MasterBase != mMasterBase) {
|
|
mMasterBase = MasterBase;
|
|
|
|
//
|
|
// Initialization sequence is needed for setting vector base.
|
|
//
|
|
|
|
//
|
|
// Preserve interrtup mask register before initialization sequence
|
|
// because it will be cleared during intialization
|
|
//
|
|
Mask = IoRead8 (LEGACY_8259_MASK_REGISTER_MASTER);
|
|
|
|
//
|
|
// ICW1: cascade mode, ICW4 write required
|
|
//
|
|
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, 0x11);
|
|
|
|
//
|
|
// ICW2: new vector base (must be multiple of 8)
|
|
//
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, mMasterBase);
|
|
|
|
//
|
|
// ICW3: slave PIC is cascaded on IRQ2
|
|
//
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x04);
|
|
|
|
//
|
|
// ICW4: fully nested mode, non-buffered mode, normal EOI, IA processor
|
|
//
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0x01);
|
|
|
|
//
|
|
// Restore interrupt mask register
|
|
//
|
|
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, Mask);
|
|
}
|
|
|
|
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);
|
|
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get the 8259 interrupt masks for Irq0 - Irq15. A different mask exists for
|
|
the legacy mode mask and the protected mode mask. The base address for the 8259
|
|
is different for legacy and protected mode, so two masks are required.
|
|
|
|
@param[in] This The PPI instance pointer.
|
|
@param[out] LegacyMask Bit 0 is Irq0 - Bit 15 is Irq15.
|
|
@param[out] LegacyEdgeLevel Bit 0 is Irq0 - Bit 15 is Irq15.
|
|
@param[out] ProtectedMask Bit 0 is Irq0 - Bit 15 is Irq15.
|
|
@param[out] ProtectedEdgeLevel Bit 0 is Irq0 - Bit 15 is Irq15.
|
|
|
|
@retval EFI_SUCCESS 8259 status returned.
|
|
@retval EFI_DEVICE_ERROR Error reading 8259.
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Interrupt8259GetMask (
|
|
IN H2O_LEGACY_8259_PPI *This,
|
|
OUT UINT16 *LegacyMask OPTIONAL,
|
|
OUT UINT16 *LegacyEdgeLevel OPTIONAL,
|
|
OUT UINT16 *ProtectedMask OPTIONAL,
|
|
OUT UINT16 *ProtectedEdgeLevel OPTIONAL
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Set the 8259 interrupt masks for Irq0 - Irq15. A different mask exists for
|
|
the legacy mode mask and the protected mode mask. The base address for the 8259
|
|
is different for legacy and protected mode, so two masks are required.
|
|
Also set the edge/level masks.
|
|
|
|
@param[in] This The PPI instance pointer.
|
|
@param[in] LegacyMask Bit 0 is Irq0 - Bit 15 is Irq15.
|
|
@param[in] LegacyEdgeLevel Bit 0 is Irq0 - Bit 15 is Irq15.
|
|
@param[in] ProtectedMask Bit 0 is Irq0 - Bit 15 is Irq15.
|
|
@param[in] ProtectedEdgeLevel Bit 0 is Irq0 - Bit 15 is Irq15.
|
|
|
|
@retval EFI_SUCCESS 8259 status returned.
|
|
@retval EFI_DEVICE_ERROR Error writing 8259.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Interrupt8259SetMask (
|
|
IN H2O_LEGACY_8259_PPI *This,
|
|
IN UINT16 *LegacyMask OPTIONAL,
|
|
IN UINT16 *LegacyEdgeLevel OPTIONAL,
|
|
IN UINT16 *ProtectedMask OPTIONAL,
|
|
IN UINT16 *ProtectedEdgeLevel OPTIONAL
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Set the 8259 mode of operation. The base address for the 8259 is different for
|
|
legacy and protected mode. The legacy mode requires the master 8259 to have a
|
|
master base of 0x08 and the slave base of 0x70. The protected mode base locations
|
|
are not defined. Interrupts must be masked by the caller before this function
|
|
is called. The interrupt mask from the current mode is saved. The interrupt
|
|
mask for the new mode is Mask, or if Mask does not exist the previously saved
|
|
mask is used.
|
|
|
|
@param[in] This The PPI instance pointer.
|
|
@param[in] Mode The mode of operation. i.e. the real mode or protected mode.
|
|
@param[in] Mask Optional interupt mask for the new mode.
|
|
@param[in] EdgeLevel Optional trigger mask for the new mode.
|
|
|
|
@retval EFI_SUCCESS 8259 programmed.
|
|
@retval EFI_DEVICE_ERROR Error writing to 8259.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Interrupt8259SetMode (
|
|
IN H2O_LEGACY_8259_PPI *This,
|
|
IN EFI_8259_MODE Mode,
|
|
IN UINT16 *Mask OPTIONAL,
|
|
IN UINT16 *EdgeLevel OPTIONAL
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Convert from IRQ to processor interrupt vector number.
|
|
|
|
@param[in] This The PPI instance pointer.
|
|
@param[in] Irq 8259 IRQ0 - IRQ15.
|
|
@param[out] Vector The processor vector number that matches an Irq.
|
|
|
|
@retval EFI_SUCCESS The Vector matching Irq is returned.
|
|
@retval EFI_INVALID_PARAMETER The Irq not valid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Interrupt8259GetVector (
|
|
IN H2O_LEGACY_8259_PPI *This,
|
|
IN EFI_8259_IRQ Irq,
|
|
OUT UINT8 *Vector
|
|
)
|
|
{
|
|
if ((UINT32)Irq > Efi8259Irq15) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Irq <= Efi8259Irq7) {
|
|
*Vector = (UINT8) (mMasterBase + Irq);
|
|
} else {
|
|
*Vector = (UINT8) (mSlaveBase + (Irq - Efi8259Irq8));
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Enables the specified IRQ.
|
|
|
|
@param[in] This The PPI instance pointer.
|
|
@param[in] Irq IRQ0-IRQ15.
|
|
@param[in] LevelTriggered 0 = Edge triggered; 1 = Level triggered.
|
|
|
|
@retval EFI_SUCCESS The Irq was enabled on the 8259 PIC.
|
|
@retval EFI_INVALID_PARAMETER The Irq is not valid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Interrupt8259EnableIrq (
|
|
IN H2O_LEGACY_8259_PPI *This,
|
|
IN EFI_8259_IRQ Irq,
|
|
IN BOOLEAN LevelTriggered
|
|
)
|
|
{
|
|
if ((UINT32)Irq > Efi8259Irq15) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
mProtectedModeMask = (UINT16) (mProtectedModeMask & ~(1 << Irq));
|
|
if (LevelTriggered) {
|
|
mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel | (1 << Irq));
|
|
} else {
|
|
mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
|
|
}
|
|
|
|
Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Disables the specified IRQ.
|
|
|
|
@param[in] This The PPI instance pointer.
|
|
@param[in] Irq IRQ0-IRQ15.
|
|
|
|
@retval EFI_SUCCESS The Irq was disabled on the 8259 PIC.
|
|
@retval EFI_INVALID_PARAMETER The Irq is not valid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Interrupt8259DisableIrq (
|
|
IN H2O_LEGACY_8259_PPI *This,
|
|
IN EFI_8259_IRQ Irq
|
|
)
|
|
{
|
|
if ((UINT32)Irq > Efi8259Irq15) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
mProtectedModeMask = (UINT16) (mProtectedModeMask | (1 << Irq));
|
|
|
|
mProtectedModeEdgeLevel = (UINT16) (mProtectedModeEdgeLevel & ~(1 << Irq));
|
|
|
|
Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
PciHandle represents a PCI config space of a PCI function. Vector
|
|
represents Interrupt Pin (from PCI config space) and it is the data
|
|
that is programmed into the Interrupt Line (from the PCI config space)
|
|
register.
|
|
|
|
@param[in] This The PPI instance pointer.
|
|
@param[in] PciHandle The PCI function to return the vector for.
|
|
@param[out] Vector The vector for the function it matches.
|
|
|
|
@retval EFI_SUCCESS A valid Vector was returned.
|
|
@retval EFI_INVALID_PARAMETER PciHandle not valid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Interrupt8259GetInterruptLine (
|
|
IN H2O_LEGACY_8259_PPI *This,
|
|
IN EFI_HANDLE PciHandle,
|
|
OUT UINT8 *Vector
|
|
)
|
|
{
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
Issues the End of Interrupt (EOI) commands to PICs.
|
|
|
|
@param[in] This The PPI instance pointer.
|
|
@param[in] Irq The interrupt for which to issue the EOI command.
|
|
|
|
@retval EFI_SUCCESS The EOI command was issued.
|
|
@retval EFI_INVALID_PARAMETER The Irq is not valid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Interrupt8259EndOfInterrupt (
|
|
IN H2O_LEGACY_8259_PPI *This,
|
|
IN EFI_8259_IRQ Irq
|
|
)
|
|
{
|
|
if ((UINT32)Irq > Efi8259Irq15) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Irq >= Efi8259Irq8) {
|
|
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_SLAVE, LEGACY_8259_EOI);
|
|
}
|
|
|
|
IoWrite8 (LEGACY_8259_CONTROL_REGISTER_MASTER, LEGACY_8259_EOI);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Driver Entry point.
|
|
|
|
@param[in] FileHandle Handle of the file being invoked.
|
|
@param[in] PeiServices Describes the list of possible PEI Services.
|
|
|
|
@retval EFI_SUCCESS One or more of the drivers returned a success code.
|
|
@retval EFI_UNSUPPORTED UnSupport in S3 Mode.
|
|
@retval Other Error installing Legacy 8259 Protocol.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Legacy8259PeimEntry (
|
|
IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
IN CONST EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_8259_IRQ Irq;
|
|
EFI_BOOT_MODE BootMode;
|
|
|
|
//
|
|
// Check bootmode, if S3 don't support
|
|
//
|
|
Status = (**PeiServices).GetBootMode (PeiServices, &BootMode);
|
|
if (BootMode == BOOT_ON_S3_RESUME) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Clear all pending interrupt
|
|
//
|
|
for (Irq = Efi8259Irq0; Irq <= Efi8259Irq15; Irq++) {
|
|
Interrupt8259EndOfInterrupt (&mInterrupt8259, Irq);
|
|
}
|
|
|
|
//
|
|
// Set the 8259 Master base to 0x68 and the 8259 Slave base to 0x70
|
|
//
|
|
Status = Interrupt8259SetVectorBase (&mInterrupt8259, PcdGet8(PcdH2OInterruptMasterBaseVector), PcdGet8(PcdH2OInterruptSlaveBaseVector));
|
|
|
|
//
|
|
// Set all 8259 interrupts to edge triggered and disabled
|
|
//
|
|
Interrupt8259WriteMask (mProtectedModeMask, mProtectedModeEdgeLevel);
|
|
|
|
//
|
|
// Install 8259 PPI
|
|
//
|
|
Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList);
|
|
|
|
return Status;
|
|
}
|