10. MCA/INIT/PMI Protocol
This document defines the basic plumbing required to run the MCA, PMI & INIT in a generic framework. They have been group together since MCA and INIT follows a very similar flow and all three have access to the min-state as defined by PAL.
It makes an attempt to bind the platform knowledge by the way of generic abstraction to the SAL MCA, PMI & INIT code. We have tried to create a private & public data structures for each CPU. For example, any CPU knowledge that should remain within the context of that CPU should be private. Any CPU knowledge that may be accessed by another CPU should be a Global Structure that can be accessed by any CPU for that domain. There are some flags that may be required globally (Sal Proc, Runtime Services, PMI, INIT, MCA) are made accessible through a protocol pointer that is described in section 5.
10.1. Machine Check and INIT
This section describes how Machine Check Abort Interrupt and INIT are handled in a UEFI 2.0 compliant system.
As shown in Early Reset, MCA and INIT flow resets, MCA and INIT follow a near identical early flow. For all three events, PAL first processes the event, save some states if needed in the min-state before jumping to SAL through the common SALE_ENTRY entry point. SAL performs some early processor initialization, save some extra states to set up an environment in which the event can be handled and then branch to the appropriate event dispatcher (normal reset flow, MCA, INIT).
MCA/INIT handling per say consists of a generic dispatcher and one or more platform specific handlers. The dispatcher is responsible for handling tasks specified in SAL specification, such as performing rendezvous, before calling the event handlers in a fixed order. The handlers are responsible for error logging, error correction and any other platform specific task required to properly handle a MCA or INIT event.
10.2. MCA Handling
The machine check (MCA) code path in a typical machine based on IPF architecture is shown in the diagram below (see Basic MCA processing flow).
MCA processing starts in PAL, running in physical mode. Control is then pass to SAL through the SALE_ENTRY entry point which in turn, after processing the MCA, pass control to the OS MCA handler.
In the PI architecture, OEMs have the choice to process MCA events in either entirely in ROM code, entirely in the RAM code or partly in ROM and partly in RAM. The early part of the MCA flow follow the SEC->PEI boot flow, with SALE_ENTRY residing in SEC while the MCA dispatcher is a PEIM dispatcher (see PI MCA processing flow). From that point on the rest of the code can reside in ROM or RAM.
When PAL hands off control to SALE_ENTRY, it will supply unique hand off state in the processor registers as well as the minimum state saved buffer area pointer called “min-state pointer”. The min-state pointer is the only context available to SALE_ENTRY. This buffer is a unique per processor save area registered to each processor during normal OS boot path.
A sample implementation is described below to clarify some of the finer points of MCA/INIT/PMI. Actual implementations may vary.
Usually, we can anchor some extra data (the MCA_INIT_PMI_PER_PROCESSOR_DATA data structure) required by the PEIM dispatcher and the MCA and INIT dispatchers to the min-state (see PI architectural data in the min).
The software component (a PEIM or a DXE module) that includes the MCA and INIT dispatchers is responsible for registering the min-state on all processors and initializing MCA_INIT_PMI_PER_PROCESSOR_DATA data structures. Only then can MCA be properly handled by the platform. To guarantee proper MCA and INIT handling, at least one handler is required to be registered with the MCA dispatcher. OEM might decide to use a monolithic handler or use multiple handlers.
The register state at the MCA dispatcher entry point is the same as the PALE_CHECK exit state with the following exceptions
GR1 contains GP for the McaDispatcherProc .
PAL saves b0 in the min-state and can be used as scratch. b0 contains the address of the McaDispatcherProc .
PAL saves static registers to the min-state. All static registers in both banks except GR16-GR20 in bank 0 can be used as scratch registers. SALE_ENTRY may freely modify these registers.
The MCA dispatcher is responsible for setting up a stack and backing store based on the values in the MCA_INIT_PMI_PER_PROCESSOR_DATA data structure. The OS stack and backing store cannot be used since they might point to virtual addresses. The MCA dispatcher is also responsible for saving any registers not saved in the min-state that may be used by the MCA handling code in the PI per processor data. Since we want to use high-level language such as C, floating point registers f2 to f31 as well as branch registers b6 and b7 must be saved. Code used during MCA handling must be compiled with /f32 option to prevent the use of registers f33-f127. Otherwise, such code is responsible for saving and restoring floating point registers f33-f127 as well as any other registers not saved in the min-state or the PI per processor data.
Note that nested MCA recovery is not supported by the Itanium architecture as PAL uses the same min-state for every MCA and INIT event. As a result, the same context within the min-state is used by PI every time the MCA dispatcher is entered.
All the MCA handles are presented in a form of an Ordered List. The head of the Ordered List is a member of the Private Data Structure. In order to reach the MCA handle Ordered List the following steps are used:
PerCpuInfoPointer = MinStatePointer ( FromSALE_CHECK ) + 4K
ThisCpuMcaPrivateData = PerCpuInfoPointer->Private
McaHandleListHead = ThisCpuMcaPrivateData->McaList
Or ((EFI_MCA_SAVE_DATA*) (((UINT8*) MinStatePointer) + 4*1024))->Private-> McaList
On reaching the Ordered List from the private data we can obtain Plabel & MCA Handle Context. Using that we can execute each handle as they appear in the ordered list.
Once the last handler has completed execution, the MCA dispatcher is responsible for deciding whether to resume execution, halt the platform or reset the platform. This is based on the OS request and platform policies. Resuming to the interrupted context is accomplished by calling PAL_MC_RESUME.
As shown in Basic MCA processing flow, the MCA handling flow requires access to certain shared hardware and software resources to support things such as error logging, error handling/correction and processor rendezvous. In addition, since MCAs are asynchronous, they might happen while other parts of the system are using those shared resources or while accessing those resources (for example during the execution of a SAL_PROC like PCI config write). We thus need a mechanism to allow shared access to two isolated model which are not aware of each others.
This is handled through the use of common code (libraries) and semaphores. The SAL PROCs and the MCAA/INIT code use the same libraries to implement any functionality shared between them such as platform reset, stall, PCI read/write. Semaphores are used to gate access to critical portion of the code and prevent multiple accesses to the same HW resource at the same time. To prevent deadlocks and guarantee proper OS handling of an MCA it might be necessary for the MCA/INIT handler to break semaphore or gets priority access to protected resources.
In addition to the previously mentioned semaphores used for gating access to HW resource, the multithreaded/MP MCA model may require an MCA specific semaphore to support things like monarch processor selection and log access. This semaphore should be visible from all processors. In addition some global are required for MCA processing to indicate a processor status (entering MCA, in MCA rendezvous, ready to enter OS MCA) with regards to the current MCA. This flags need to have a global scope since the MCA monarch may need to access them to make sure all processor are where they are supposed to be.
10.3. INIT Handling
Most of what have been defined for the MCA handling and dispatcher applies to the INIT code path. The early part of the INIT code path, up to the INIT dispatcher is identical to the MCA code path while some of the INIT handler code, like logging, can be shared with the MCA handler.
The INIT code path in a typical machine based on IPF architecture is shown in the diagram below.
Like MCA, INIT processing starts in the PAL code in physical mode and then flows into PI code (OEM firmware code) through SALE_ENTRY. The INIT dispatcher is responsible for setting up a stack and backing store, saving the floating point registers before calling any code that may be written in higher level languages. At that point the dispatcher is ready to call the INIT handlers. As with MCA only one handler is required to exist but OEMs are free to implement a monolithic handler or use multiple handlers. Once the last handler has been executed, the dispatcher will resume to the interrupted context or reset the platform based on the OS request.
The MCA handler limitations regarding access to shared HW and SW resources applies to the INIT handler, as such library code and common semaphores should be used.
INIT events are always local to each processor. As a result we do not need INIT specific flags or semaphore in the MCA_INIT_PMI_PER_PROCESSOR_DATA data structures.
10.4. PMI
This section describes how PMI, platform management interrupts, are handled in EFI 2.0 compliant system. PMIs provide an operating system-independent interrupt mechanism to support OEM and vendor specific hardware event.
As shown in PMI handling flow, PMI handling is pretty similar to MCA and INIT handling in such that it consists of a generic dispatcher and one of more platform specific handlers. The dispatchers is the SAL PMI entry point (SALE_PMI) and is responsible for saving state and setting up the environment for the handler to execute. Contrary to MCA and INIT, PAL does not save any context in the min-state and it is the responsibility of the PMI dispatcher to save state. Since the min-state is available during PMI handling (PAL provides its address to the SAL PMI handler) the MCA_INIT_PMI_PER_PROCESSOR_DATA data structure present in the min-state can be used. However an MCA/INIT event occurring while PMI is being would preclude the system from resuming from the PMI event. To alleviate this, a platform may decide to implement a separate copy of the MCA_INIT_PMI_PER_PROCESSOR_DATA data structure out side of the min-state, to be used for PMI state saving.
Once the state is saved, the platform specific PMI handlers are found using the order handler list provided in the private data structure. The mechanism used is the same one used in MCA and INIT handling.
10.5. Event Handlers
The events handlers are called by the various dispatchers.
10.5.1. MCA Handlers
MCA Handler
typedef
EFI_STATUS
SAL_RUNTIMESERVICE
(EFIAPI *EFI_SAL_MCA_HANDLER) (
IN VOID *ModuleGlobal,
IN UINT64 ProcessorStateParameters ,
IN EFI_PHYSICAL_ADDRESS MinstateBase,
IN UINT64 RendezvouseStateInformation,
IN UINT64 CpuIndex,
IN SAL_MCA_COUNT_STRUCTURE *McaCountStructure,
IN OUT BOOLEAN *CorrectedMachineCheck
);
Parameters
- ModuleGlobal
The context of MCA Handler.
- ProcessorStateParameters
The processor state parameters (PSP),
- MinstateBase
Base address of the min-state.
- RendezvousStateInformation
Rendezvous state information to be passedto the OS on OS MCA entry. Refer to the SalSpecification 3.0 , section 4.8 for moreinformation.
- CpuIndex
Index of the logical processor
- McaCountStructure
Pointer to the MCA records structure
- CorrectedMachineCheck
This flag is set to TRUE is the MCA hasbeen corrected by the handler or by a previoushandler.
#pragma pack(1)
//
// MCA Records Structure
//
typedef struct {
UINT64 First : 1;
UINT64 Last : 1;
UINT64 EntryCount : 16;
UINT64 DispatchedCount : 16;
UINT64 Reserved : 30;
} SAL_MCA_COUNT_STRUCTURE;
#pragma pack ()
10.5.2. INIT Handlers
INIT Handler
typedef
EFI_STATUS
SAL_RUNTIMESERVICE
(EFIAPI *EFI_SAL_INIT_HANDLER) (
IN VOID *ModuleGlobal,
IN UINT64 ProcessorStateParameters,
IN EFI_PHYSICAL_ADDRESS MinstateBase,
IN BOOLEAN McaInProgress,
IN UINT64 CpuIndex,
IN SAL_MCA_COUNT_STRUCTURE *McaCountStructure,
OUT BOOLEAN *DumpSwitchPressed
);
Parameters
- ModuleGlobal
The context of MCA Handler.
- ProcessorStateParameters
The processor state parameters (PSP),
- MinstateBase
Base address of the min-state.
- McaInProgress
This flag indicates if an MCA is inprogress.
- CpuIndex
Index of the logical processor
- McaCountStructure
Pointer to the MCA records structure
- DumpSwitchPressed
This flag indicates the crash dump switchhas been pressed.
10.5.3. PMI Handlers
PMI Handler
typedef
EFI_STATUS
(EFIAPI *SAL_PMI_HANDLER) (
IN VOID *ModuleGlobal,
IN UINT64 CpuIndex,
IN UINT64 PmiVector
);
Description
- ModuleGlobal
The context of MCA Handler.
- CpuIndex
Index of the logical processor
- PmiVector
The PMI vector number as received from thePALE_PMI exit state (GR24).
10.6. MCA PMI INIT Protocol
Summary
This protocol is used to register MCA, INIT and PMI handlers with their respective dispatcher.
GUID
#define EFI_SAL_MCA_INIT_PMI_PROTOCOL_GUID \
{
0xb60dc6e8,0x3b6f,0x11d5,0xaf,0x9,0x0,0xa0,0xc9,0x44,0xa0,0x5b }
Protocol Interface Structure
typedef struct {
EFI_SAL_REGISTER_MCA_HANDLER RegisterMcaHandler;
EFI_SAL_REGISTER_INIT_HANDLER RegisterInitHandler;
EFI_SAL_REGISTER_PMI_HANDLER RegisterPmiHandler;
BOOLEAN McaInProgress;
BOOLEAN InitInProgress;
BOOLEAN PmiInProgress;
} EFI_SAL_MCA_INIT_PMI_PROTOCOL;
Parameters
- RegisterMcaHandler
Function to register a MCA handler.
- RegisterInitHandler
Function to register an INIT handler.
- RegisterPmiHandler
Function to register a PMI hander.
- McaInProgress
Whether MCA handler is in progress
- InitInProgress
Whether Init handler is in progress
- PmiInProgress
Whether Pmi handler is in progress
10.6.1. EFI_SAL_MCA_INIT_PMI_PROTOCOL. RegisterMcaHandler()
Summary
Register a MCA handler with the MCA dispatcher.
Prototype
typedef
EFI_STATUS
(EFIAPI *EFI_SAL_REGISTER_MCA_HANDLER) (
IN struct _EFI_SAL_MCA_INIT_PMI_PROTOCOL *This,
IN EFI_SAL_MCA_HANDLER McaHandler,
IN VOID ModuleGlobal
IN BOOLEAN MakeFirst,
IN BOOLEAN MakeLast
);
Parameters
- This
The EFI_SAL_MCA_INIT_PMI_PROTOCOL instance.
- McaHandler
The MCA handler to register as defined in:ref:MCAHandlers.
- ModuleGlobal
The context of the MCA Handler.
- MakeFirst
This flag specifies the handler should bemade first in the list.
- MakeLast
This flag specifies the handler should bemade last in the list.
Status Codes Returned
EFI_SUCCESS |
MCA Handle was registered |
EFI_OUT_OF_RESOURCES |
No more resources to register an MCA handler |
EFI_INVALID_PARAMETER |
Invalid parameters were passed. |
10.6.2. EFI_SAL_MCA_INIT_PMI_PROTOCOL. RegisterInitHandler()
Summary
Register an INIT handler with the INIT dispatcher.
Prototype
typedef
EFI_STATUS
(EFIAPI *EFI_SAL_REGISTER_INIT_HANDLER) (
IN struct _EFI_SAL_MCA_INIT_PMI_PROTOCOL *This,
IN EFI_SAL_INIT_HANDLER InitHandler,
IN VOID ModuleGlobal
IN BOOLEAN MakeFirst,
IN BOOLEAN MakeLast
);
Parameters
- This
The EFI_SAL_MCA_INIT_PMI_PROTOCOL instance.
- InitHandler
The INIT handler to register as defined in:ref:INITHandlers
- ModuleGlobal
The context of the INIT Handler.
- MakeFirst
This flag specifies the handler should bemade first in the list.
- MakeLast
This flag specifies the handler should bemade last in the list.
Status Codes Returned
EFI_SUCCESS |
INIT Handle was registered |
EFI_OUT_OF_RESOURCES |
No more resources to register an INIT handler |
EFI_INVALID_PARAMETER |
Invalid parameters were passed. |
10.6.3. EFI_SAL_MCA_INIT_PMI_PROTOCOL. RegisterPmiHandler()
Summary
Register a PMI handler with the PMI dispatcher.
Prototype
typedef
EFI_STATUS
(EFIAPI *EFI_SAL_REGISTER_PMI_HANDLER) (
IN struct _EFI_SAL_MCA_INIT_PMI_PROTOCOL *This,
IN EFI_SAL_PMI_HANDLER PmiHandler,
IN VOID ModuleGlobal
IN BOOLEAN MakeFirst,
IN BOOLEAN MakeLast
);
Parameters
- This
The EFI_SAL_MCA_INIT_PMI_PROTOCOL instance.
- PmiHandler
The PMI handler to register as defined in:ref:PMIHandlers.
- ModuleGlobal
The context of the PMI Handler.
- MakeFirst
This flag specifies the handler should bemade first in the list.
- MakeLast
This flag specifies the handler should bemade last in the list.
Status Codes Returned
EFI_SUCCESS |
INIT Handle was registered |
EFI_OUT_OF_RESOURCES |
No more resources to register a PMI handler |
EFI_INVALID_PARAMETER |
Invalid parameters were passed. |