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.

_images/V4_MCA_INIT_PMI_Protocol-2.png

Fig. 10.3 Early Reset, MCA and INIT flow

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).

_images/V4_MCA_INIT_PMI_Protocol-3.png

Fig. 10.4 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.

_images/V4_MCA_INIT_PMI_Protocol-4.png

Fig. 10.5 PI MCA processing flow

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).

_images/V4_MCA_INIT_PMI_Protocol-5.png

Fig. 10.6 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:

  1. PerCpuInfoPointer = MinStatePointer ( FromSALE_CHECK ) + 4K

  2. ThisCpuMcaPrivateData = PerCpuInfoPointer->Private

  3. 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.

_images/V4_MCA_INIT_PMI_Protocol-6.png

Fig. 10.7 PI INIT processing flow

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.

_images/V4_MCA_INIT_PMI_Protocol-7.png

Fig. 10.8 PMI handling flow

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.