/** @file Prototypes and defines for the QNC SMM Dispatcher. Copyright (c) 2013-2016 Intel Corporation. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef QNC_SMM_H #define QNC_SMM_H // // Include common header file for this module. // #include "CommonHeader.h" #include "QNCSmmRegisters.h" extern EFI_HANDLE mQNCSmmDispatcherImageHandle; // // ///////////////////////////////////////////////////////////////////////////// // SUPPORTED PROTOCOLS // // // Define an enumeration for all the supported protocols // typedef enum { // UsbType, DELETE:on QuarkNcSocId, there is no usb smi supported SxType, SwType, GpiType, QNCnType, PowerButtonType, PeriodicTimerType, NUM_PROTOCOLS } QNC_SMM_PROTOCOL_TYPE; // // ///////////////////////////////////////////////////////////////////////////// // SPECIFYING A REGISTER // We want a general way of referring to addresses. For this case, we'll only // need addresses in the ACPI table (and the TCO entries within the ACPI table). // However, it's interesting to consider what it would take to support other types // of addresses. To address Will's concern, I think it prudent to accommodate it // early on in the design. // // Addresses we need to consider: // // Type: Required: // I/O Yes // ACPI (special case of I/O) Only if we want to // TCO (special case of ACPI) Only if we want to // Memory (or Memory Mapped I/O) Only if we want to // PCI Yes, for BiosWp // typedef enum { // // IO_ADDR_TYPE, // unimplemented // ACPI_ADDR_TYPE, GPE_ADDR_TYPE, // // MEMORY_ADDR_TYPE, // unimplemented // MEMORY_MAPPED_IO_ADDRESS_TYPE, PCI_ADDR_TYPE, NUM_ADDR_TYPES, // count of items in this enum QNC_SMM_ADDR_TYPE_NULL = -1 // sentinel to indicate NULL or to signal end of arrays } ADDR_TYPE; // // Assumption: 32-bits -- enum's evaluate to integer // Assumption: This code will only run on IA-32. Justification: IA-64 doesn't have SMIs. // We don't have to worry about 64-bit addresses. // Typedef the size of addresses in case the numbers I'm using are wrong or in case // this changes. This is a good idea because PCI_ADDR will change, for example, when // we add support for PciExpress. // typedef UINT16 IO_ADDR; typedef IO_ADDR ACPI_ADDR; // can omit typedef IO_ADDR GPE_ADDR; // can omit typedef IO_ADDR TCO_ADDR; // can omit typedef VOID *MEM_ADDR; typedef MEM_ADDR MEMORY_MAPPED_IO_ADDRESS; typedef union { UINT32 Raw; struct { UINT8 Reg; UINT8 Fnc; UINT8 Dev; UINT8 Bus; } Fields; } PCI_ADDR; typedef struct { ADDR_TYPE Type; union { // // used to initialize during declaration/definition // UINTN raw; // // used to access useful data // IO_ADDR io; ACPI_ADDR acpi; GPE_ADDR gpe; TCO_ADDR tco; MEM_ADDR mem; MEMORY_MAPPED_IO_ADDRESS Mmio; PCI_ADDR pci; } Data; } QNC_SMM_ADDRESS; // // Assumption: total size is 64 bits (32 for type and 32 for data) or 8 bytes // #define EFI_PCI_ADDRESS_PORT 0xcf8 #define EFI_PCI_DATA_PORT 0xcfc // // ///////////////////////////////////////////////////////////////////////////// // SPECIFYING BITS WITHIN A REGISTER // Here's a struct that helps us specify a source or enable bit. // typedef struct { QNC_SMM_ADDRESS Reg; UINT8 SizeInBytes; // of the register UINT8 Bit; } QNC_SMM_BIT_DESC; // // Sometimes, we'll have bit descriptions that are unused. It'd be great to have a // way to easily identify them: // #define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type == QNC_SMM_ADDR_TYPE_NULL) // "returns" true when BitDesc is NULL #define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = QNC_SMM_ADDR_TYPE_NULL) // will "return" an integer w/ value of 0 #define NULL_BIT_DESC_INITIALIZER \ { \ { \ QNC_SMM_ADDR_TYPE_NULL, \ { \ 0 \ } \ }, \ 0, 0 \ } // // I'd like a type to specify the callback's Sts & En bits because they'll // be commonly used together: // #define NUM_EN_BITS 2 #define NUM_STS_BITS 1 // // Flags // typedef UINT8 QNC_SMM_SOURCE_FLAGS; // // Flags required today // #define QNC_SMM_NO_FLAGS 0 #define QNC_SMM_SCI_EN_DEPENDENT (BIT0) #define QNC_SMM_CLEAR_WITH_ZERO (BIT6) // // Flags that might be required tomorrow // #define QNC_SMM_CLEAR_WITH_ONE 2 // may need to support bits that clear by writing 0 // #define QNC_SMM_MULTIBIT_FIELD 3 // may need to support status/enable fields 2 bits wide // typedef struct { QNC_SMM_SOURCE_FLAGS Flags; QNC_SMM_BIT_DESC En[NUM_EN_BITS]; QNC_SMM_BIT_DESC Sts[NUM_STS_BITS]; } QNC_SMM_SOURCE_DESC; // // 31 bytes, I think // #define NULL_SOURCE_DESC_INITIALIZER \ { \ QNC_SMM_NO_FLAGS, \ { \ NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \ }, \ { \ NULL_BIT_DESC_INITIALIZER \ } \ } // // ///////////////////////////////////////////////////////////////////////////// // CHILD CONTEXTS // To keep consistent w/ the architecture, we'll need to provide the context // to the child when we call its callback function. After talking with Will, // we agreed that we'll need functions to "dig" the context out of the hardware // in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those // contexts to prevent unnecessary dispatches. I'd like a general type for these // "GetContext" functions, so I'll need a union of all the protocol contexts for // our internal use: // typedef union { // // (in no particular order) // EFI_SMM_ICHN_REGISTER_CONTEXT QNCn; EFI_SMM_SX_REGISTER_CONTEXT Sx; EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer; EFI_SMM_SW_REGISTER_CONTEXT Sw; EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton; // EFI_SMM_USB_REGISTER_CONTEXT Usb; DELETE:on QuarkNcSocId, there is no usb smi supported EFI_SMM_GPI_REGISTER_CONTEXT Gpi; } QNC_SMM_CONTEXT; typedef union { // // (in no particular order) // EFI_SMM_SW_CONTEXT Sw; EFI_SMM_PERIODIC_TIMER_CONTEXT PeriodicTimer; } QNC_SMM_BUFFER; // // Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes // typedef struct _DATABASE_RECORD DATABASE_RECORD; typedef VOID (EFIAPI *GET_CONTEXT) ( IN DATABASE_RECORD * Record, OUT QNC_SMM_CONTEXT * Context ); // // Assumption: the GET_CONTEXT function will be as small and simple as possible. // Assumption: We don't need to pass in an enumeration for the protocol because each // GET_CONTEXT function is written for only one protocol. // We also need a function to compare contexts to see if the child should be dispatched // typedef BOOLEAN (EFIAPI *CMP_CONTEXT) ( IN QNC_SMM_CONTEXT * Context1, IN QNC_SMM_CONTEXT * Context2 ); /* Returns: True when contexts are equivalent; False otherwise */ // // This function is used to get the content of CommBuffer that will be passed // to Callback function // typedef VOID (EFIAPI *GET_BUFFER) ( IN DATABASE_RECORD * Record ); // // Finally, every protocol will require a "Get Context", "Compare Context" // and "Get CommBuffer" call, so we may as well wrap that up in a table, too. // typedef struct { GET_CONTEXT GetContext; CMP_CONTEXT CmpContext; GET_BUFFER GetBuffer; } CONTEXT_FUNCTIONS; extern CONTEXT_FUNCTIONS ContextFunctions[NUM_PROTOCOLS]; // // ///////////////////////////////////////////////////////////////////////////// // MAPPING CONTEXT TO BIT DESCRIPTIONS // I'd like to have a general approach to mapping contexts to bit descriptions. // Sometimes, we'll find that we can use table lookups or CONSTant assignments; // other times, we'll find that we'll need to use a function to perform the mapping. // If we define a macro to mask that process, we'll never have to change the code. // I don't know if this is desirable or not -- if it isn't, then we can get rid // of the macros and just use function calls or variable assignments. Doesn't matter // to me. // Mapping complex contexts requires a function // // DELETE:on QuarkNcSocId, there is no usb smi supported //EFI_STATUS //EFIAPI //MapUsbToSrcDesc ( // IN QNC_SMM_CONTEXT *RegisterContext, // OUT QNC_SMM_SOURCE_DESC *SrcDesc // ) /*++ Routine Description: GC_TODO: Add function description Arguments: RegisterContext - GC_TODO: add argument description SrcDesc - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; EFI_STATUS MapPeriodicTimerToSrcDesc ( IN QNC_SMM_CONTEXT *RegisterContext, OUT QNC_SMM_SOURCE_DESC *SrcDesc ) /*++ Routine Description: GC_TODO: Add function description Arguments: RegisterContext - GC_TODO: add argument description SrcDesc - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; // // Mapping simple contexts can be done by assignment or lookup table // extern CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC; extern CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC; // // With the changes we've made to the protocols, we can now use table // lookups for the following protocols: // extern CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC; extern QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES]; // // For QNCx, APMC is UINT8 port, so the MAX SWI Value is 0xFF. // #define MAXIMUM_SWI_VALUE 0xFF // // Open: Need to make sure this kind of type cast will actually work. // May need an intermediate form w/ two VOID* arguments. I'll figure // that out when I start compiling. /////////////////////////////////////////////////////////////////////////////// // typedef VOID (EFIAPI *QNC_SMM_CLEAR_SOURCE) ( QNC_SMM_SOURCE_DESC * SrcDesc ); // // ///////////////////////////////////////////////////////////////////////////// // "DATABASE" RECORD // Linked list data structures // #define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C') struct _DATABASE_RECORD { UINT32 Signature; LIST_ENTRY Link; BOOLEAN Processed; // // Status and Enable bit description // QNC_SMM_SOURCE_DESC SrcDesc; // // Callback function // EFI_SMM_HANDLER_ENTRY_POINT2 Callback; QNC_SMM_CONTEXT ChildContext; VOID *CallbackContext; QNC_SMM_BUFFER CommBuffer; UINTN BufferSize; // // Special handling hooks -- init them to NULL if unused/unneeded // QNC_SMM_CLEAR_SOURCE ClearSource; // needed for SWSMI timer // Functions required to make callback code general // CONTEXT_FUNCTIONS ContextFunctions; // // The protocol that this record dispatches // QNC_SMM_PROTOCOL_TYPE ProtocolType; }; #define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE) #define DATABASE_RECORD_FROM_CONTEXT(_record) CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE) // // ///////////////////////////////////////////////////////////////////////////// // HOOKING INTO THE ARCHITECTURE // typedef EFI_STATUS (EFIAPI *QNC_SMM_GENERIC_REGISTER) ( IN VOID **This, IN VOID *DispatchFunction, IN VOID *RegisterContext, OUT EFI_HANDLE * DispatchHandle ); typedef EFI_STATUS (EFIAPI *QNC_SMM_GENERIC_UNREGISTER) ( IN VOID **This, IN EFI_HANDLE DispatchHandle ); // // Define a memory "stamp" equivalent in size and function to most of the protocols // typedef struct { QNC_SMM_GENERIC_REGISTER Register; QNC_SMM_GENERIC_UNREGISTER Unregister; UINTN Extra1; UINTN Extra2; // may not need this one } QNC_SMM_GENERIC_PROTOCOL; EFI_STATUS QNCSmmCoreRegister ( IN QNC_SMM_GENERIC_PROTOCOL *This, IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, IN QNC_SMM_CONTEXT *RegisterContext, OUT EFI_HANDLE *DispatchHandle ) /*++ Routine Description: GC_TODO: Add function description Arguments: This - GC_TODO: add argument description DispatchFunction - GC_TODO: add argument description RegisterContext - GC_TODO: add argument description DispatchHandle - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; EFI_STATUS QNCSmmCoreUnRegister ( IN QNC_SMM_GENERIC_PROTOCOL *This, IN EFI_HANDLE DispatchHandle ) /*++ Routine Description: GC_TODO: Add function description Arguments: This - GC_TODO: add argument description DispatchHandle - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; typedef union { QNC_SMM_GENERIC_PROTOCOL Generic; // EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; DELETE:on QuarkNcSocId, there is no usb smi supported EFI_SMM_SX_DISPATCH2_PROTOCOL Sx; EFI_SMM_SW_DISPATCH2_PROTOCOL Sw; EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi; EFI_SMM_ICHN_DISPATCH2_PROTOCOL QNCn; EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton; EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer; } QNC_SMM_PROTOCOL; // // Define a structure to help us identify the generic protocol // #define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T') typedef struct { UINTN Signature; QNC_SMM_PROTOCOL_TYPE Type; EFI_GUID *Guid; QNC_SMM_PROTOCOL Protocols; } QNC_SMM_QUALIFIED_PROTOCOL; #define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \ CR (_generic, \ QNC_SMM_QUALIFIED_PROTOCOL, \ Protocols, \ PROTOCOL_SIGNATURE \ ) // // Create private data for the protocols that we'll publish // typedef struct { LIST_ENTRY CallbackDataBase; EFI_HANDLE SmiHandle; EFI_HANDLE InstallMultProtHandle; QNC_SMM_QUALIFIED_PROTOCOL Protocols[NUM_PROTOCOLS]; } PRIVATE_DATA; extern PRIVATE_DATA mPrivateData; // // ///////////////////////////////////////////////////////////////////////////// // VOID EFIAPI SwGetContext ( IN DATABASE_RECORD *Record, OUT QNC_SMM_CONTEXT *Context ) /*++ Routine Description: GC_TODO: Add function description Arguments: Record - GC_TODO: add argument description Context - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; BOOLEAN EFIAPI SwCmpContext ( IN QNC_SMM_CONTEXT *Context1, IN QNC_SMM_CONTEXT *Context2 ) /*++ Routine Description: GC_TODO: Add function description Arguments: Context1 - GC_TODO: add argument description Context2 - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; VOID SwGetBuffer ( IN DATABASE_RECORD * Record ) /*++ Routine Description: GC_TODO: Add function description Arguments: Record - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; VOID EFIAPI SxGetContext ( IN DATABASE_RECORD *Record, OUT QNC_SMM_CONTEXT *Context ) /*++ Routine Description: GC_TODO: Add function description Arguments: Record - GC_TODO: add argument description Context - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; BOOLEAN EFIAPI SxCmpContext ( IN QNC_SMM_CONTEXT *Context1, IN QNC_SMM_CONTEXT *Context2 ) /*++ Routine Description: GC_TODO: Add function description Arguments: Context1 - GC_TODO: add argument description Context2 - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; VOID EFIAPI PeriodicTimerGetContext ( IN DATABASE_RECORD *Record, OUT QNC_SMM_CONTEXT *Context ) /*++ Routine Description: GC_TODO: Add function description Arguments: Record - GC_TODO: add argument description Context - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; BOOLEAN EFIAPI PeriodicTimerCmpContext ( IN QNC_SMM_CONTEXT *Context1, IN QNC_SMM_CONTEXT *Context2 ) /*++ Routine Description: GC_TODO: Add function description Arguments: Context1 - GC_TODO: add argument description Context2 - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; VOID PeriodicTimerGetBuffer ( IN DATABASE_RECORD * Record ) /*++ Routine Description: GC_TODO: Add function description Arguments: Record - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; VOID EFIAPI PowerButtonGetContext ( IN DATABASE_RECORD *Record, OUT QNC_SMM_CONTEXT *Context ) /*++ Routine Description: GC_TODO: Add function description Arguments: Record - GC_TODO: add argument description Context - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; BOOLEAN EFIAPI PowerButtonCmpContext ( IN QNC_SMM_CONTEXT *Context1, IN QNC_SMM_CONTEXT *Context2 ) /*++ Routine Description: GC_TODO: Add function description Arguments: Context1 - GC_TODO: add argument description Context2 - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; // // ///////////////////////////////////////////////////////////////////////////// // VOID EFIAPI QNCSmmPeriodicTimerClearSource ( QNC_SMM_SOURCE_DESC *SrcDesc ) /*++ Routine Description: GC_TODO: Add function description Arguments: SrcDesc - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; EFI_STATUS QNCSmmPeriodicTimerDispatchGetNextShorterInterval ( IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, IN OUT UINT64 **SmiTickInterval ) /*++ Routine Description: GC_TODO: Add function description Arguments: This - GC_TODO: add argument description SmiTickInterval - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; VOID QNCSmmSxGoToSleep ( VOID ) /*++ Routine Description: GC_TODO: Add function description Arguments: None Returns: GC_TODO: add return values --*/ ; VOID EFIAPI QNCSmmQNCnClearSource ( QNC_SMM_SOURCE_DESC *SrcDesc ) /*++ Routine Description: GC_TODO: Add function description Arguments: SrcDesc - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ ; #endif