blob: e5228dd7ff9a7d148782a0bd10b6d416c0e797ee [file] [log] [blame]
/*++
Copyright (c) 2013 Intel Corporation.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Module Name:
QNCSmm.h
Abstract:
Prototypes and defines for the QNC SMM Dispatcher.
--*/
#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;
//
// Status and Enable bit description
//
QNC_SMM_SOURCE_DESC SrcDesc;
//
// Callback function
//
EFI_SMM_HANDLER_ENTRY_POINT2 Callback;
QNC_SMM_CONTEXT ChildContext;
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