Add STM, bios and test package.

This commit is contained in:
Jiewen Yao 2016-03-31 15:15:57 +08:00
commit 3da9a66044
963 changed files with 212662 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,160 @@
/** @file
Definitions for CPU S3 data.
Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _ACPI_CPU_DATA_H_
#define _ACPI_CPU_DATA_H_
//
// Register types in register table
//
typedef enum {
Msr,
ControlRegister,
MemoryMapped,
CacheControl
} REGISTER_TYPE;
//
// Element of register table entry
//
typedef struct {
REGISTER_TYPE RegisterType;
UINT32 Index;
UINT8 ValidBitStart;
UINT8 ValidBitLength;
UINT64 Value;
} CPU_REGISTER_TABLE_ENTRY;
//
// Register table definition, including current table length,
// allocated size of this table, and pointer to the list of table entries.
//
typedef struct {
//
// The number of valid entries in the RegisterTableEntry buffer
//
UINT32 TableLength;
UINT32 NumberBeforeReset;
//
// The size, in bytes, of the RegisterTableEntry buffer
//
UINT32 AllocatedSize;
//
// The initial APIC ID of the CPU this register table applies to
//
UINT32 InitialApicId;
//
// Buffer of CPU_REGISTER_TABLE_ENTRY structures. This buffer must be
// allocated below 4GB from memory of type EfiACPIMemoryNVS.
//
CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
} CPU_REGISTER_TABLE;
//
// Data structure that is required for ACPI S3 resume. This structure must be
// allocated below 4GB from memory of type EfiACPIMemoryNVS. The PCD
// PcdCpuS3DataAddress must be set to the physical address where this structure
// is allocated
//
typedef struct {
//
// Physical address of 4KB buffer allocated below 1MB from memory of type
// EfiReservedMemoryType. The buffer is not required to be initialized, but
// it is recommended that the buffer be zero-filled. This buffer is used to
// wake APs during an ACPI S3 resume.
//
EFI_PHYSICAL_ADDRESS StartupVector;
//
// Physical address of structure of type IA32_DESCRIPTOR. This structure must
// be allocated below 4GB from memory of type EfiACPIMemoryNVS. The
// IA32_DESCRIPTOR structure provides the base address and length of a GDT
// The buffer for GDT must also be allocated below 4GB from memory of type
// EfiACPIMemoryNVS. The GDT must be filled in with the GDT contents that are
// used during an ACPI S3 resume. This is typically the contents of the GDT
// used by the boot processor when the platform is booted.
//
EFI_PHYSICAL_ADDRESS GdtrProfile;
//
// Physical address of structure of type IA32_DESCRIPTOR. This structure must
// be allocated below 4GB from memory of type EfiACPIMemoryNVS. The
// IA32_DESCRIPTOR structure provides the base address and length of an IDT.
// The buffer for IDT must also be allocated below 4GB from memory of type
// EfiACPIMemoryNVS. The IDT must be filled in with the IDT contents that are
// used during an ACPI S3 resume. This is typically the contents of the IDT
// used by the boot processor when the platform is booted.
//
EFI_PHYSICAL_ADDRESS IdtrProfile;
//
// Physical address of a buffer that is used as stacks during ACPI S3 resume.
// The total size of this buffer, in bytes, is NumberOfCpus * StackSize. This
// structure must be allocated below 4GB from memory of type EfiACPIMemoryNVS.
//
EFI_PHYSICAL_ADDRESS StackAddress;
//
// The size, in bytes, of the stack provided to each CPU during ACPI S3 resume.
//
UINT32 StackSize;
//
// The number of CPUs. If a platform does not support hot plug CPUs, then
// this is the number of CPUs detected when the platform is booted, regardless
// of being enabled or disabled. If a platform does support hot plug CPUs,
// then this is the maximum number of CPUs that the platform supports.
//
UINT32 NumberOfCpus;
//
// Physical address of structure of type MTRR_SETTINGS that contains a copy
// of the MTRR settings that are compatible with the MTRR settings used by
// the boot processor when the platform was booted. These MTRR settings are
// used during an ACPI S3 resume. This structure must be allocated below 4GB
// from memory of type EfiACPIMemoryNVS.
//
EFI_PHYSICAL_ADDRESS MtrrTable;
//
// Physical address of an array of CPU_REGISTER_TABLE structures, with
// NumberOfCpus entries. This array must be allocated below 4GB from memory
// of type EfiACPIMemoryNVS. If a register table is not required, then the
// TableLength and AllocatedSize fields of CPU_REGISTER_TABLE are set to 0.
// If TableLength is > 0, then elements of RegisterTableEntry are used to
// initialize the CPU that matches InitialApicId, during an ACPI S3 resume,
// before SMBASE relocation is performed.
//
EFI_PHYSICAL_ADDRESS PreSmmInitRegisterTable;
//
// Physical address of an array of CPU_REGISTER_TABLE structures, with
// NumberOfCpus entries. This array must be allocated below 4GB from memory
// of type EfiACPIMemoryNVS. If a register table is not required, then the
// TableLength and AllocatedSize fields of CPU_REGISTER_TABLE are set to 0.
// If TableLength is > 0, then elements of RegisterTableEntry are used to
// initialize the CPU that matches InitialApicId, during an ACPI S3 resume,
// after SMBASE relocation is performed.
//
EFI_PHYSICAL_ADDRESS RegisterTable;
//
// Physical address of a buffer that contains the machine check handler that
// is used during an ACPI S3 Resume. This buffer must be allocated below 4GB
// from memory of type EfiACPIMemoryNVS. In order for this machine check
// handler to be active on an AP during an ACPI S3 resume, the machine check
// vector in the IDT provided by IdtrProfile must be initialized to transfer
// control to this physical address.
//
EFI_PHYSICAL_ADDRESS ApMachineCheckHandlerBase;
//
// The size, in bytes, of the machine check handler that is used during an
// ACPI S3 Resume. If this field is 0, then a machine check handler is not
// provided.
//
UINT32 ApMachineCheckHandlerSize;
} ACPI_CPU_DATA;
#endif

View File

@ -0,0 +1,33 @@
/** @file
Definition for a structure sharing information for CPU hot plug.
Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _CPU_HOT_PLUG_DATA_H_
#define _CPU_HOT_PLUG_DATA_H_
#define CPU_HOT_PLUG_DATA_REVISION_1 0x00000001
typedef struct {
UINT32 Revision; // Used for version identification for this structure
UINT32 ArrayLength; // The entries number of the following ApicId array and SmBase array
//
// Data required for SMBASE relocation
//
UINT64 *ApicId; // Pointer to ApicId array
UINTN *SmBase; // Pointer to SmBase array
UINT32 Reserved;
UINT32 SmrrBase;
UINT32 SmrrSize;
} CPU_HOT_PLUG_DATA;
#endif

View File

@ -0,0 +1,25 @@
/** @file
Provides the data format and Name and GUID definition for MsegHob.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _MSEG_SMRAM_H_
#define _MSEG_SMRAM_H_
#define MSEG_SMRAM_GUID \
{ \
0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 } \
}
extern EFI_GUID gMsegSmramGuid;
#endif

View File

@ -0,0 +1,416 @@
/** @file
Library that provides CPU specific functions to support the PiSmmCpuDxeSmm module.
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __SMM_FEATURES_LIB_H__
#define __SMM_FEATURES_LIB_H__
#include <Protocol/MpService.h>
#include <Protocol/SmmCpu.h>
#include <Register/SmramSaveStateMap.h>
#include <CpuHotPlugData.h>
///
/// Enumeration of SMM registers that are accessed using the library functions
/// SmmCpuFeaturesIsSmmRegisterSupported (), SmmCpuFeaturesGetSmmRegister (),
/// and SmmCpuFeaturesSetSmmRegister ().
///
typedef enum {
///
/// Read-write register to provides access to MSR_SMM_FEATURE_CONTROL if the
/// CPU supports this MSR.
///
SmmRegFeatureControl,
///
/// Read-only register that returns a non-zero value if the CPU is able to
/// respond to SMIs.
///
SmmRegSmmEnable,
///
/// Read-only register that returns a non-zero value if the CPU is able to
/// respond to SMIs, but is busy with other actions that are causing a delay
/// in responding to an SMI. This register abstracts access to MSR_SMM_DELAYED
/// if the CPU supports this MSR.
///
SmmRegSmmDelayed,
///
/// Read-only register that returns a non-zero value if the CPU is able to
/// respond to SMIs, but is busy with other actions that are blocking its
/// ability to respond to an SMI. This register abstracts access to
/// MSR_SMM_BLOCKED if the CPU supports this MSR.
///
SmmRegSmmBlocked
} SMM_REG_NAME;
/**
Called during the very first SMI into System Management Mode to initialize
CPU features, including SMBASE, for the currently executing CPU. Since this
is the first SMI, the SMRAM Save State Map is at the default address of
SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing
CPU is specified by CpuIndex and CpuIndex can be used to access information
about the currently executing CPU in the ProcessorInfo array and the
HotPlugCpuData data structure.
@param[in] CpuIndex The index of the CPU to initialize. The value
must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that
was elected as monarch during System Management
Mode initialization.
FALSE if the CpuIndex is not the index of the CPU
that was elected as monarch during System
Management Mode initialization.
@param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION
structures. ProcessorInfo[CpuIndex] contains the
information for the currently executing CPU.
@param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that
contains the ApidId and SmBase arrays.
**/
VOID
EFIAPI
SmmCpuFeaturesInitializeProcessor (
IN UINTN CpuIndex,
IN BOOLEAN IsMonarch,
IN EFI_PROCESSOR_INFORMATION *ProcessorInfo,
IN CPU_HOT_PLUG_DATA *CpuHotPlugData
);
/**
This function updates the SMRAM save state on the currently executing CPU
to resume execution at a specific address after an RSM instruction. This
function must evaluate the SMRAM save state to determine the execution mode
the RSM instruction resumes and update the resume execution address with
either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart
flag in the SMRAM save state must always be cleared. This function returns
the value of the instruction pointer from the SMRAM save state that was
replaced. If this function returns 0, then the SMRAM save state was not
modified.
This function is called during the very first SMI on each CPU after
SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
to signal that the SMBASE of each CPU has been updated before the default
SMBASE address is used for the first SMI to the next CPU.
@param[in] CpuIndex The index of the CPU to hook. The value
must be between 0 and the NumberOfCpus
field in the System Management System Table
(SMST).
@param[in] CpuState Pointer to SMRAM Save State Map for the
currently executing CPU.
@param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
32-bit execution mode from 64-bit SMM.
@param[in] NewInstructionPointer Instruction pointer to use if resuming to
same execution mode as SMM.
@retval 0 This function did modify the SMRAM save state.
@retval > 0 The original instruction pointer value from the SMRAM save state
before it was replaced.
**/
UINT64
EFIAPI
SmmCpuFeaturesHookReturnFromSmm (
IN UINTN CpuIndex,
IN SMRAM_SAVE_STATE_MAP *CpuState,
IN UINT64 NewInstructionPointer32,
IN UINT64 NewInstructionPointer
);
/**
Hook point in normal execution mode that allows the one CPU that was elected
as monarch during System Management Mode initialization to perform additional
initialization actions immediately after all of the CPUs have processed their
first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
**/
VOID
EFIAPI
SmmCpuFeaturesSmmRelocationComplete (
VOID
);
/**
Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
returned, then a custom SMI handler is not provided by this library,
and the default SMI handler must be used.
@retval 0 Use the default SMI handler.
@retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
The caller is required to allocate enough SMRAM for each CPU to
support the size of the custom SMI handler.
**/
UINTN
EFIAPI
SmmCpuFeaturesGetSmiHandlerSize (
VOID
);
/**
Return the offset to SMBASE, of a custom native SMI Handler in bytes.
If 0 is returned, then a custom SMI handler is not provided by this library,
and the default SMI handler must be used.
@retval 0 Use the default SMI handler.
@retval > 0 If STM is enabled, TXT_PROCESSOR_SMM_DESCRIPTOR.SmmSmiHandlerRip
is SmiHandlerOffset + SMBASE.
**/
UINTN
EFIAPI
SmmCpuFeaturesGetSmiHandlerOffset (
VOID
);
/**
Install a custom SMI handler for the CPU specified by CpuIndex. This function
is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
than zero and is called by the CPU that was elected as monarch during System
Management Mode initialization.
@param[in] CpuIndex The index of the CPU to install the custom SMI handler.
The value must be between 0 and the NumberOfCpus field
in the System Management System Table (SMST).
@param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
@param[in] SmiStack The stack to use when an SMI is processed by the
the CPU specified by CpuIndex.
@param[in] StackSize The size, in bytes, if the stack used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtBase The base address of the GDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtBase The base address of the IDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] Cr3 The base address of the page tables to use when an SMI
is processed by the CPU specified by CpuIndex.
**/
VOID
EFIAPI
SmmCpuFeaturesInstallSmiHandler (
IN UINTN CpuIndex,
IN UINT32 SmBase,
IN VOID *SmiStack,
IN UINTN StackSize,
IN UINTN GdtBase,
IN UINTN GdtSize,
IN UINTN IdtBase,
IN UINTN IdtSize,
IN UINT32 Cr3
);
/**
Determines if MTRR registers must be configured to set SMRAM cache-ability
when executing in System Management Mode.
@retval TRUE MTRR registers must be configured to set SMRAM cache-ability.
@retval FALSE MTRR registers do not need to be configured to set SMRAM
cache-ability.
**/
BOOLEAN
EFIAPI
SmmCpuFeaturesNeedConfigureMtrrs (
VOID
);
/**
Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
returns TRUE.
**/
VOID
EFIAPI
SmmCpuFeaturesDisableSmrr (
VOID
);
/**
Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
returns TRUE.
**/
VOID
EFIAPI
SmmCpuFeaturesReenableSmrr (
VOID
);
/**
Processor specific hook point each time a CPU enters System Management Mode.
@param[in] CpuIndex The index of the CPU that has entered SMM. The value
must be between 0 and the NumberOfCpus field in the
System Management System Table (SMST).
**/
VOID
EFIAPI
SmmCpuFeaturesRendezvousEntry (
IN UINTN CpuIndex
);
/**
Processor specific hook point each time a CPU exits System Management Mode.
@param[in] CpuIndex The index of the CPU that is exiting SMM. The value must
be between 0 and the NumberOfCpus field in the System
Management System Table (SMST).
**/
VOID
EFIAPI
SmmCpuFeaturesRendezvousExit (
IN UINTN CpuIndex
);
/**
Check to see if an SMM register is supported by a specified CPU.
@param[in] CpuIndex The index of the CPU to check for SMM register support.
The value must be between 0 and the NumberOfCpus field
in the System Management System Table (SMST).
@param[in] RegName Identifies the SMM register to check for support.
@retval TRUE The SMM register specified by RegName is supported by the CPU
specified by CpuIndex.
@retval FALSE The SMM register specified by RegName is not supported by the
CPU specified by CpuIndex.
**/
BOOLEAN
EFIAPI
SmmCpuFeaturesIsSmmRegisterSupported (
IN UINTN CpuIndex,
IN SMM_REG_NAME RegName
);
/**
Returns the current value of the SMM register for the specified CPU.
If the SMM register is not supported, then 0 is returned.
@param[in] CpuIndex The index of the CPU to read the SMM register. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] RegName Identifies the SMM register to read.
@return The value of the SMM register specified by RegName from the CPU
specified by CpuIndex.
**/
UINT64
EFIAPI
SmmCpuFeaturesGetSmmRegister (
IN UINTN CpuIndex,
IN SMM_REG_NAME RegName
);
/**
Sets the value of an SMM register on a specified CPU.
If the SMM register is not supported, then no action is performed.
@param[in] CpuIndex The index of the CPU to write the SMM register. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] RegName Identifies the SMM register to write.
registers are read-only.
@param[in] Value The value to write to the SMM register.
**/
VOID
EFIAPI
SmmCpuFeaturesSetSmmRegister (
IN UINTN CpuIndex,
IN SMM_REG_NAME RegName,
IN UINT64 Value
);
/**
Read an SMM Save State register on the target processor. If this function
returns EFI_UNSUPPORTED, then the caller is responsible for reading the
SMM Save Sate register.
@param[in] CpuIndex The index of the CPU to read the SMM Save State. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] Register The SMM Save State register to read.
@param[in] Width The number of bytes to read from the CPU save state.
@param[out] Buffer Upon return, this holds the CPU register value read
from the save state.
@retval EFI_SUCCESS The register was read from Save State.
@retval EFI_INVALID_PARAMTER Buffer is NULL.
@retval EFI_UNSUPPORTED This function does not support reading Register.
**/
EFI_STATUS
EFIAPI
SmmCpuFeaturesReadSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
OUT VOID *Buffer
);
/**
Writes an SMM Save State register on the target processor. If this function
returns EFI_UNSUPPORTED, then the caller is responsible for writing the
SMM Save Sate register.
@param[in] CpuIndex The index of the CPU to write the SMM Save State. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] Register The SMM Save State register to write.
@param[in] Width The number of bytes to write to the CPU save state.
@param[in] Buffer Upon entry, this holds the new CPU register value.
@retval EFI_SUCCESS The register was written to Save State.
@retval EFI_INVALID_PARAMTER Buffer is NULL.
@retval EFI_UNSUPPORTED This function does not support writing Register.
**/
EFI_STATUS
EFIAPI
SmmCpuFeaturesWriteSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
IN CONST VOID *Buffer
);
/**
This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
notification is completely processed.
**/
VOID
EFIAPI
SmmCpuFeaturesCompleteSmmReadyToLock (
VOID
);
/**
This API provides a method for a CPU to allocate a specific region for storing page tables.
This API can be called more once to allocate memory for page tables.
Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
is returned. If there is not enough memory remaining to satisfy the request, then NULL is
returned.
This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM.
@param Pages The number of 4 KB pages to allocate.
@return A pointer to the allocated buffer for page tables.
@retval NULL Fail to allocate a specific region for storing page tables,
Or there is no preference on where the page tables are allocated in SMRAM.
**/
VOID *
EFIAPI
SmmCpuFeaturesAllocatePageTableMemory (
IN UINTN Pages
);
#endif

View File

@ -0,0 +1,109 @@
/** @file
Public include file for the SMM CPU Platform Hook Library.
Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __SMM_CPU_PLATFORM_HOOK_LIB_H__
#define __SMM_CPU_PLATFORM_HOOK_LIB_H__
///
/// SMM Page Size Type
///
typedef enum {
SmmPageSize4K,
SmmPageSize2M,
SmmPageSize1G,
MaxSmmPageSizeType
} SMM_PAGE_SIZE_TYPE;
/**
Checks if platform produces a valid SMI.
This function checks if platform produces a valid SMI. This function is
called at SMM entry to detect if this is a spurious SMI. This function
must be implemented in an MP safe way because it is called by multiple CPU
threads.
@retval TRUE There is a valid SMI
@retval FALSE There is no valid SMI
**/
BOOLEAN
EFIAPI
PlatformValidSmi (
VOID
);
/**
Clears platform top level SMI status bit.
This function clears platform top level SMI status bit.
@retval TRUE The platform top level SMI status is cleared.
@retval FALSE The platform top level SMI status cannot be cleared.
**/
BOOLEAN
EFIAPI
ClearTopLevelSmiStatus (
VOID
);
/**
Performs platform specific way of SMM BSP election.
This function performs platform specific way of SMM BSP election.
@param IsBsp Output parameter. TRUE: the CPU this function executes
on is elected to be the SMM BSP. FALSE: the CPU this
function executes on is to be SMM AP.
@retval EFI_SUCCESS The function executes successfully.
@retval EFI_NOT_READY The function does not determine whether this CPU should be
BSP or AP. This may occur if hardware init sequence to
enable the determination is yet to be done, or the function
chooses not to do BSP election and will let SMM CPU driver to
use its default BSP election process.
@retval EFI_DEVICE_ERROR The function cannot determine whether this CPU should be
BSP or AP due to hardware error.
**/
EFI_STATUS
EFIAPI
PlatformSmmBspElection (
OUT BOOLEAN *IsBsp
);
/**
Get platform page table attribute .
This function gets page table attribute of platform.
@param Address Input parameter. Obtain the page table entries attribute on this address.
@param PageSize Output parameter. The size of the page.
@param NumOfPages Output parameter. Number of page.
@param PageAttribute Output parameter. Paging Attributes (WB, UC, etc).
@retval EFI_SUCCESS The platform page table attribute from the address is determined.
@retval EFI_UNSUPPORTED The platform does not support getting page table attribute for the address.
**/
EFI_STATUS
EFIAPI
GetPlatformPageTableAttribute (
IN UINT64 Address,
OUT SMM_PAGE_SIZE_TYPE *PageSize,
OUT UINTN *NumOfPages,
OUT UINTN *PageAttribute
);
#endif

View File

@ -0,0 +1,141 @@
/** @file
STM service protocol definition
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SM_MONITOR_INIT_PROTOCOL_H_
#define _SM_MONITOR_INIT_PROTOCOL_H_
#include <Uefi.h>
#include <StmApi.h>
#define EFI_SM_MONITOR_INIT_PROTOCOL_GUID \
{ 0x228f344d, 0xb3de, 0x43bb, 0xa4, 0xd7, 0xea, 0x20, 0xb, 0x1b, 0x14, 0x82}
//
// STM service
//
/**
Load STM image to MSEG.
@param StmImage STM image
@param StmImageSize STM image size
@retval EFI_SUCCESS Load STM to MSEG successfully
@retval EFI_ALREADY_STARTED STM image is already loaded to MSEG
@retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
@retval EFI_UNSUPPORTED MSEG is not enabled
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SM_MONITOR_LOAD_MONITOR) (
IN EFI_PHYSICAL_ADDRESS StmImage,
IN UINTN StmImageSize
);
/**
Add resources in list to database.
@param ResourceList A pointer to resource list to be added
@param NumEntries Optional number of entries.
If 0, list must be terminated by END_OF_RESOURCES.
@retval EFI_SUCCESS If resources are added
@retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
@retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SM_MONITOR_ADD_PI_RESOURCE) (
IN STM_RSC *ResourceList,
IN UINT32 NumEntries OPTIONAL
);
/**
Delete resources in list to database.
@param ResourceList A pointer to resource list to be deleted
NULL means delete all resources.
@param NumEntries Optional number of entries.
If 0, list must be terminated by END_OF_RESOURCES.
@retval EFI_SUCCESS If resources are deleted
@retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SM_MONITOR_DELETE_PI_RESOURCE) (
IN STM_RSC *ResourceList OPTIONAL,
IN UINT32 NumEntries OPTIONAL
);
/**
Get BIOS resources.
@param ResourceList A pointer to resource list to be filled
@param ResourceSize On input it means size of resource list input.
On output it means size of resource list filled,
or the size of resource list to be filled if size of too small.
@retval EFI_SUCCESS If resources are returned.
@retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SM_MONITOR_GET_PI_RESOURCE) (
OUT STM_RSC *ResourceList,
IN OUT UINT32 *ResourceSize
);
typedef UINT32 EFI_SM_MONITOR_STATE;
#define EFI_SM_MONITOR_STATE_ENABLED 0x1
#define EFI_SM_MONITOR_STATE_ACTIVATED 0x2
/**
Get STM state
@return STM state
**/
typedef
EFI_SM_MONITOR_STATE
(EFIAPI *EFI_SM_MONITOR_GET_MONITOR_STATE) (
VOID
);
typedef struct _EFI_SM_MONITOR_INIT_PROTOCOL {
//
// Valid at boot-time only
//
EFI_SM_MONITOR_LOAD_MONITOR LoadMonitor;
EFI_SM_MONITOR_ADD_PI_RESOURCE AddPiResource;
EFI_SM_MONITOR_DELETE_PI_RESOURCE DeletePiResource;
EFI_SM_MONITOR_GET_PI_RESOURCE GetPiResource;
//
// Valid at runtime
//
EFI_SM_MONITOR_GET_MONITOR_STATE GetMonitorState;
} EFI_SM_MONITOR_INIT_PROTOCOL;
extern EFI_GUID gEfiSmMonitorInitProtocolGuid;
#endif

View File

@ -0,0 +1,209 @@
/** @file
SMM CPU Service protocol definition.
Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SMM_CPU_SERVICE_PROTOCOL_H_
#define _SMM_CPU_SERVICE_PROTOCOL_H_
//
// Share some definitions with MP Services and CPU Arch Protocol
//
#include <Protocol/MpService.h>
#include <Protocol/Cpu.h>
#define EFI_SMM_CPU_SERVICE_PROTOCOL_GUID \
{ \
0x1d202cab, 0xc8ab, 0x4d5c, { 0x94, 0xf7, 0x3c, 0xfc, 0xc0, 0xd3, 0xd3, 0x35 } \
}
typedef struct _EFI_SMM_CPU_SERVICE_PROTOCOL EFI_SMM_CPU_SERVICE_PROTOCOL;
//
// Protocol functions
//
/**
Gets processor information on the requested processor at the
instant this call is made. This service may only be called from the BSP.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL
instance.
@param[in] ProcessorNumber The handle number of processor.
@param[out] ProcessorInfoBuffer A pointer to the buffer where information for
the requested processor is deposited.
@retval EFI_SUCCESS Processor information was returned.
@retval EFI_DEVICE_ERROR The calling processor is an AP.
@retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
@retval EFI_NOT_FOUND The processor with the handle specified by
ProcessorNumber does not exist in the platform.
**/
typedef
EFI_STATUS
(EFIAPI * EFI_SMM_GET_PROCESSOR_INFO) (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINTN ProcessorNumber,
OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
);
/**
This service switches the requested AP to be the BSP from that point onward.
This service changes the BSP for all purposes. This call can only be performed
by the current BSP.
This service switches the requested AP to be the BSP from that point onward.
This service changes the BSP for all purposes. The new BSP can take over the
execution of the old BSP and continue seamlessly from where the old one left
off.
If the BSP cannot be switched prior to the return from this service, then
EFI_UNSUPPORTED must be returned.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorNumber The handle number of AP that is to become the new
BSP. The range is from 0 to the total number of
logical processors minus 1.
@retval EFI_SUCCESS BSP successfully switched.
@retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
this service returning.
@retval EFI_UNSUPPORTED Switching the BSP is not supported.
@retval EFI_SUCCESS The calling processor is an AP.
@retval EFI_NOT_FOUND The processor with the handle specified by
ProcessorNumber does not exist.
@retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
a disabled AP.
@retval EFI_NOT_READY The specified AP is busy.
**/
typedef
EFI_STATUS
(EFIAPI * EFI_SMM_SWITCH_BSP) (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINTN ProcessorNumber
);
/**
Notify that a new processor has been added to the system.
The SMM CPU driver should add the processor to the SMM CPU list.
If the processor is disabled it won't participate any SMI handler during subsequent SMIs.
@param This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param ProcessorId The hardware ID of the processor.
@param ProcessorNumber The handle number of processor.
@param ProcessorResource A pointer to EFI_SMM_PROCESSOR_RESOURCE which holds the assigned resources.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_ALREADY_STARTED Processor already present.
@retval EFI_NOT_READY Space for a new handle could not be allocated.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SMM_ADD_PROCESSOR) (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINT64 ProcessorId,
OUT UINTN *ProcessorNumber
);
/**
Notify that a processor is hot-removed.
Remove a processor from the CPU list of the SMM CPU driver. After this API is called, the removed processor
must not respond to SMIs in the coherence domain.
@param This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param ProcessorId The hardware ID of the processor.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_NOT_FOUND Processor with the hardware ID specified by ProcessorId does not exist.
@retval EFI_NOT_READY Specified AP is busy.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SMM_REMOVE_PROCESSOR) (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINTN ProcessorNumber
);
/**
This return the handle number for the calling processor. This service may be
called from the BSP and APs.
This service returns the processor handle number for the calling processor.
The returned value is in the range from 0 to the total number of logical
processors minus 1. This service may be called from the BSP and APs.
If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
is returned. Otherwise, the current processors handle number is returned in
ProcessorNumber, and EFI_SUCCESS is returned.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorNumber The handle number of AP that is to become the new
BSP. The range is from 0 to the total number of
logical processors minus 1.
@retval EFI_SUCCESS The current processor handle number was returned
in ProcessorNumber.
@retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
**/
typedef
EFI_STATUS
(EFIAPI * EFI_SMM_WHOAMI) (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
OUT UINTN *ProcessorNumber
);
/**
Register exception handler.
@param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.
@param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and
the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL
of the UEFI 2.0 specification.
@param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER
that is called when a processor interrupt occurs.
If this parameter is NULL, then the handler will be uninstalled.
@retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed.
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.
@retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SMM_REGISTER_EXCEPTION_HANDLER) (
IN EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
);
//
// This protocol provides CPU services from SMM.
//
struct _EFI_SMM_CPU_SERVICE_PROTOCOL {
EFI_SMM_GET_PROCESSOR_INFO GetProcessorInfo;
EFI_SMM_SWITCH_BSP SwitchBsp;
EFI_SMM_ADD_PROCESSOR AddProcessor;
EFI_SMM_REMOVE_PROCESSOR RemoveProcessor;
EFI_SMM_WHOAMI WhoAmI;
EFI_SMM_REGISTER_EXCEPTION_HANDLER RegisterExceptionHandler;
};
extern EFI_GUID gEfiSmmCpuServiceProtocolGuid;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,190 @@
/** @file
SMRAM Save State Map Definitions.
SMRAM Save State Map definitions based on contents of the
Intel(R) 64 and IA-32 Architectures Software Developer's Manual
Volume 3C, Section 34.4 SMRAM
Volume 3C, Section 34.5 SMI Handler Execution Environment
Volume 3C, Section 34.7 Managing Synchronous and Asynchronous SMIs
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __SMRAM_SAVE_STATE_MAP_H__
#define __SMRAM_SAVE_STATE_MAP_H__
///
/// Default SMBASE address
///
#define SMM_DEFAULT_SMBASE 0x30000
///
/// Offset of SMM handler from SMBASE
///
#define SMM_HANDLER_OFFSET 0x8000
///
/// Offset of SMRAM Save State Map from SMBASE
///
#define SMRAM_SAVE_STATE_MAP_OFFSET 0xfc00
#pragma pack (1)
///
/// 32-bit SMRAM Save State Map
///
typedef struct {
UINT8 Reserved[0x200]; // 7c00h
// Padded an extra 0x200 bytes so 32-bit and 64-bit
// SMRAM Save State Maps are the same size
UINT8 Reserved1[0xf8]; // 7e00h
UINT32 SMBASE; // 7ef8h
UINT32 SMMRevId; // 7efch
UINT16 IORestart; // 7f00h
UINT16 AutoHALTRestart; // 7f02h
UINT8 Reserved2[0x9C]; // 7f08h
UINT32 IOMemAddr; // 7fa0h
UINT32 IOMisc; // 7fa4h
UINT32 _ES; // 7fa8h
UINT32 _CS; // 7fach
UINT32 _SS; // 7fb0h
UINT32 _DS; // 7fb4h
UINT32 _FS; // 7fb8h
UINT32 _GS; // 7fbch
UINT32 Reserved3; // 7fc0h
UINT32 _TR; // 7fc4h
UINT32 _DR7; // 7fc8h
UINT32 _DR6; // 7fcch
UINT32 _EAX; // 7fd0h
UINT32 _ECX; // 7fd4h
UINT32 _EDX; // 7fd8h
UINT32 _EBX; // 7fdch
UINT32 _ESP; // 7fe0h
UINT32 _EBP; // 7fe4h
UINT32 _ESI; // 7fe8h
UINT32 _EDI; // 7fech
UINT32 _EIP; // 7ff0h
UINT32 _EFLAGS; // 7ff4h
UINT32 _CR3; // 7ff8h
UINT32 _CR0; // 7ffch
} SMRAM_SAVE_STATE_MAP32;
///
/// 64-bit SMRAM Save State Map
///
typedef struct {
UINT8 Reserved1[0x1d0]; // 7c00h
UINT32 GdtBaseHiDword; // 7dd0h
UINT32 LdtBaseHiDword; // 7dd4h
UINT32 IdtBaseHiDword; // 7dd8h
UINT8 Reserved2[0xc]; // 7ddch
UINT64 IO_EIP; // 7de8h
UINT8 Reserved3[0x50]; // 7df0h
UINT32 _CR4; // 7e40h
UINT8 Reserved4[0x48]; // 7e44h
UINT32 GdtBaseLoDword; // 7e8ch
UINT32 Reserved5; // 7e90h
UINT32 IdtBaseLoDword; // 7e94h
UINT32 Reserved6; // 7e98h
UINT32 LdtBaseLoDword; // 7e9ch
UINT8 Reserved7[0x38]; // 7ea0h
UINT64 EptVmxControl; // 7ed8h
UINT32 EnEptVmxControl; // 7ee0h
UINT8 Reserved8[0x14]; // 7ee4h
UINT32 SMBASE; // 7ef8h
UINT32 SMMRevId; // 7efch
UINT16 IORestart; // 7f00h
UINT16 AutoHALTRestart; // 7f02h
UINT8 Reserved9[0x18]; // 7f04h
UINT64 _R15; // 7f1ch
UINT64 _R14;
UINT64 _R13;
UINT64 _R12;
UINT64 _R11;
UINT64 _R10;
UINT64 _R9;
UINT64 _R8;
UINT64 _RAX; // 7f5ch
UINT64 _RCX;
UINT64 _RDX;
UINT64 _RBX;
UINT64 _RSP;
UINT64 _RBP;
UINT64 _RSI;
UINT64 _RDI;
UINT64 IOMemAddr; // 7f9ch
UINT32 IOMisc; // 7fa4h
UINT32 _ES; // 7fa8h
UINT32 _CS;
UINT32 _SS;
UINT32 _DS;
UINT32 _FS;
UINT32 _GS;
UINT32 _LDTR; // 7fc0h
UINT32 _TR;
UINT64 _DR7; // 7fc8h
UINT64 _DR6;
UINT64 _RIP; // 7fd8h
UINT64 IA32_EFER; // 7fe0h
UINT64 _RFLAGS; // 7fe8h
UINT64 _CR3; // 7ff0h
UINT64 _CR0; // 7ff8h
} SMRAM_SAVE_STATE_MAP64;
///
/// Union of 32-bit and 64-bit SMRAM Save State Maps
///
typedef union {
SMRAM_SAVE_STATE_MAP32 x86;
SMRAM_SAVE_STATE_MAP64 x64;
} SMRAM_SAVE_STATE_MAP;
///
/// Minimum SMM Revision ID that supports IOMisc field in SMRAM Save State Map
///
#define SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC 0x30004
///
/// SMRAM Save State Map IOMisc I/O Length Values
///
#define SMM_IO_LENGTH_BYTE 0x01
#define SMM_IO_LENGTH_WORD 0x02
#define SMM_IO_LENGTH_DWORD 0x04
///
/// SMRAM Save State Map IOMisc I/O Instruction Type Values
///
#define SMM_IO_TYPE_IN_IMMEDIATE 0x9
#define SMM_IO_TYPE_IN_DX 0x1
#define SMM_IO_TYPE_OUT_IMMEDIATE 0x8
#define SMM_IO_TYPE_OUT_DX 0x0
#define SMM_IO_TYPE_INS 0x3
#define SMM_IO_TYPE_OUTS 0x2
#define SMM_IO_TYPE_REP_INS 0x7
#define SMM_IO_TYPE_REP_OUTS 0x6
///
/// SMRAM Save State Map IOMisc structure
///
typedef union {
struct {
UINT32 SmiFlag:1;
UINT32 Length:3;
UINT32 Type:4;
UINT32 Reserved1:8;
UINT32 Port:16;
} Bits;
UINT32 Uint32;
} SMRAM_SAVE_STATE_IOMISC;
#pragma pack ()
#endif

View File

@ -0,0 +1,732 @@
/** @file
STM API definition
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _STM_API_H_
#define _STM_API_H_
// definition in STM spec
#define STM_SPEC_VERSION_MAJOR 1
#define STM_SPEC_VERSION_MINOR 0
#pragma pack (push, 1)
#define STM_HARDWARE_FIELD_FILL_TO_2K (2048 - sizeof(UINT32) * 8)
typedef struct {
UINT32 StmHeaderRevision;
UINT32 MonitorFeatures;
UINT32 GdtrLimit;
UINT32 GdtrBaseOffset;
UINT32 CsSelector;
UINT32 EipOffset;
UINT32 EspOffset;
UINT32 Cr3Offset;
UINT8 Reserved[STM_HARDWARE_FIELD_FILL_TO_2K];
} HARDWARE_STM_HEADER;
#define STM_FEATURES_IA32E 0x1
typedef struct {
UINT32 Intel64ModeSupported :1; // bitfield
UINT32 EptSupported :1; // bitfield
UINT32 Reserved :30; // must be 0
} STM_FEAT;
typedef struct {
UINT8 StmSpecVerMajor;
UINT8 StmSpecVerMinor;
UINT16 Reserved; // must be zero
UINT32 StaticImageSize;
UINT32 PerProcDynamicMemorySize;
UINT32 AdditionalDynamicMemorySize;
STM_FEAT StmFeatures;
UINT32 NumberOfRevIDs;
UINT32 StmSmmRevID[1];
//
// The total STM_HEADER should be 4K.
//
} SOFTWARE_STM_HEADER;
typedef struct {
HARDWARE_STM_HEADER HwStmHdr;
SOFTWARE_STM_HEADER SwStmHdr;
} STM_HEADER;
#define SHA1 1
#define SHA256 2
typedef struct {
UINT64 BiosComponentBase;
UINT32 ImageSize;
UINT32 HashAlgorithm; // SHA1 or SHA256
UINT8 Hash[32];
} TXT_BIOS_COMPONENT_STATUS;
#define PAGE_SIZE 4096
typedef struct {
UINT32 ImageSize;
UINT32 Reserved;
UINT64 ImagePageBase[1]; //[NumberOfPages];
} TXT_BIOS_COMPONENT_UPDATE;
// If (ImageSizeInBytes % PAGE_SIZE == 0) {
// NumberOfPages = ImageSizeInBytes / PAGE_SIZE
// } else {
// NumberOfPages = ImageSizeInBytes / PAGE_SIZE + 1
// }
typedef struct {
UINT64 SpeRip;
UINT64 SpeRsp;
UINT16 SpeSs;
UINT16 PageViolationException:1;
UINT16 MsrViolationException:1;
UINT16 RegisterViolationException:1;
UINT16 IoViolationException:1;
UINT16 PciViolationException:1;
UINT16 Reserved1:11;
UINT32 Reserved2;
} STM_PROTECTION_EXCEPTION_HANDLER;
typedef struct {
UINT8 ExecutionDisableOutsideSmrr:1;
UINT8 Intel64Mode:1;
UINT8 Cr4Pae : 1;
UINT8 Cr4Pse : 1;
UINT8 Reserved1 : 4;
} STM_SMM_ENTRY_STATE;
typedef struct {
UINT8 SmramToVmcsRestoreRequired : 1; // BIOS restore hint
UINT8 ReinitializeVmcsRequired : 1; // BIOS request
UINT8 Reserved2 : 6;
} STM_SMM_RESUME_STATE;
typedef struct {
UINT8 DomainType : 4; // STM input to BIOS on each SMI
UINT8 XStatePolicy : 2; // STM input to BIOS on each SMI
UINT8 EptEnabled : 1;
UINT8 Reserved3 : 1;
} STM_SMM_STATE;
typedef struct {
UINT64 Signature;
UINT16 Size;
UINT8 SmmDescriptorVerMajor;
UINT8 SmmDescriptorVerMinor;
UINT32 LocalApicId;
STM_SMM_ENTRY_STATE SmmEntryState;
STM_SMM_RESUME_STATE SmmResumeState;
STM_SMM_STATE StmSmmState;
UINT8 Reserved4;
UINT16 SmmCs;
UINT16 SmmDs;
UINT16 SmmSs;
UINT16 SmmOtherSegment;
UINT16 SmmTr;
UINT16 Reserved5;
UINT64 SmmCr3;
UINT64 SmmStmSetupRip;
UINT64 SmmStmTeardownRip;
UINT64 SmmSmiHandlerRip;
UINT64 SmmSmiHandlerRsp;
UINT64 SmmGdtPtr;
UINT32 SmmGdtSize;
UINT32 RequiredStmSmmRevId;
STM_PROTECTION_EXCEPTION_HANDLER StmProtectionExceptionHandler;
UINT64 Reserved6;
UINT64 BiosHwResourceRequirementsPtr;
// extend area
UINT64 AcpiRsdp;
UINT8 PhysicalAddressBits;
} TXT_PROCESSOR_SMM_DESCRIPTOR;
#define TXT_PROCESSOR_SMM_DESCRIPTOR_SIGNATURE SIGNATURE_64('T', 'X', 'T', 'P', 'S', 'S', 'I', 'G')
#define TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MAJOR 1
#define TXT_PROCESSOR_SMM_DESCRIPTOR_VERSION_MINOR 0
typedef enum {
TxtSmmPageViolation = 1,
TxtSmmMsrViolation,
TxtSmmRegisterViolation,
TxtSmmIoViolation,
TxtSmmPciViolation
} TXT_SMM_PROTECTION_EXCEPTION_TYPE;
typedef struct {
UINT32 Rdi;
UINT32 Rsi;
UINT32 Rbp;
UINT32 Rdx;
UINT32 Rcx;
UINT32 Rbx;
UINT32 Rax;
UINT32 Cr3;
UINT32 Cr2;
UINT32 Cr0;
UINT32 VmcsExitInstructionInfo;
UINT32 VmcsExitInstructionLength;
UINT64 VmcsExitQualification;
UINT32 ErrorCode; // TXT_SMM_PROTECTION_EXCEPTION_TYPE
UINT32 Rip;
UINT32 Cs;
UINT32 Rflags;
UINT32 Rsp;
UINT32 Ss;
} STM_PROTECTION_EXCEPTION_STACK_FRAME_IA32;
typedef struct {
UINT64 R15;
UINT64 R14;
UINT64 R13;
UINT64 R12;
UINT64 R11;
UINT64 R10;
UINT64 R9;
UINT64 R8;
UINT64 Rdi;
UINT64 Rsi;
UINT64 Rbp;
UINT64 Rdx;
UINT64 Rcx;
UINT64 Rbx;
UINT64 Rax;
UINT64 Cr8;
UINT64 Cr3;
UINT64 Cr2;
UINT64 Cr0;
UINT64 VmcsExitInstructionInfo;
UINT64 VmcsExitInstructionLength;
UINT64 VmcsExitQualification;
UINT64 ErrorCode; // TXT_SMM_PROTECTION_EXCEPTION_TYPE
UINT64 Rip;
UINT64 Cs;
UINT64 Rflags;
UINT64 Rsp;
UINT64 Ss;
} STM_PROTECTION_EXCEPTION_STACK_FRAME_X64;
typedef union {
STM_PROTECTION_EXCEPTION_STACK_FRAME_IA32 *Ia32StackFrame;
STM_PROTECTION_EXCEPTION_STACK_FRAME_X64 *X64StackFrame;
} STM_PROTECTION_EXCEPTION_STACK_FRAME;
#define STM_SMM_REV_ID 0x80010100
typedef struct _STM_SMM_CPU_STATE {
UINT8 Reserved1[0x1d0]; // fc00h
UINT32 GdtBaseHiDword; // fdd0h : NO
UINT32 LdtBaseHiDword; // fdd4h : NO
UINT32 IdtBaseHiDword; // fdd8h : NO
UINT8 Reserved2[0x4]; // fddch
UINT64 IoRdi; // fde0h : NO - restricted
UINT64 IoEip; // fde8h : YES
UINT64 IoRcx; // fdf0h : NO - restricted
UINT64 IoRsi; // fdf8h : NO - restricted
UINT8 Reserved3[0x40]; // fe00h
UINT32 Cr4; // fe40h : NO
UINT8 Reserved4[0x48]; // fe44h
UINT32 GdtBaseLoDword; // fe8ch : NO
UINT32 GdtLimit; // fe90h : NO - RESTRICTED
UINT32 IdtBaseLoDword; // fe94h : NO
UINT32 IdtLimit; // fe98h : NO - RESTRICTED
UINT32 LdtBaseLoDword; // fe9ch : NO
UINT32 LdtLimit; // fea0h : NO - RESTRICTED
UINT32 LdtInfo; // fea4h : NO - RESTRICTED
UINT8 Reserved5[0x30]; // fea8h
UINT64 Eptp; // fed8h : NO
UINT32 EnabledEPT; // fee0h : NO
UINT8 Reserved6[0x14]; // fee4h
UINT32 Smbase; // fef8h : YES - NO for STM
UINT32 SMMRevId; // fefch : NO
UINT16 IORestart; // ff00h : YES
UINT16 AutoHALTRestart; // ff02h : YES
UINT8 Reserved7[0x18]; // ff04h
UINT64 R15; // ff1ch : YES
UINT64 R14; // ff24h : YES
UINT64 R13; // ff2ch : YES
UINT64 R12; // ff34h : YES
UINT64 R11; // ff3ch : YES
UINT64 R10; // ff44h : YES
UINT64 R9; // ff4ch : YES
UINT64 R8; // ff54h : YES
UINT64 Rax; // ff5ch : YES
UINT64 Rcx; // ff64h : YES
UINT64 Rdx; // ff6ch : YES
UINT64 Rbx; // ff74h : YES
UINT64 Rsp; // ff7ch : YES
UINT64 Rbp; // ff84h : YES
UINT64 Rsi; // ff8ch : YES
UINT64 Rdi; // ff94h : YES
UINT64 IOMemAddr; // ff9ch : NO
UINT32 IOMisc; // ffa4h : NO
UINT32 Es; // ffa8h : NO
UINT32 Cs; // ffach : NO
UINT32 Ss; // ffb0h : NO
UINT32 Ds; // ffb4h : NO
UINT32 Fs; // ffb8h : NO
UINT32 Gs; // ffbch : NO
UINT32 Ldtr; // ffc0h : NO
UINT32 Tr; // ffc4h : NO
UINT64 Dr7; // ffc8h : NO
UINT64 Dr6; // ffd0h : NO
UINT64 Rip; // ffd8h : YES
UINT64 Ia32Efer; // ffe0h : YES - NO for STM
UINT64 Rflags; // ffe8h : YES
UINT64 Cr3; // fff0h : NO
UINT64 Cr0; // fff8h : NO
} STM_SMM_CPU_STATE;
//
// STM Mapping
//
typedef struct {
UINT64 PhysicalAddress;
UINT64 VirtualAddress;
UINT32 PageCount;
UINT32 PatCacheType;
} STM_MAP_ADDRESS_RANGE_DESCRIPTOR;
#define ST_UC 0x00
#define WC 0x01
#define WT 0x04
#define WP 0x05
#define WB 0x06
#define UC 0x07
#define FOLLOW_MTRR 0xFFFFFFFF
typedef struct {
UINT64 VirtualAddress;
UINT32 Length;
} STM_UNMAP_ADDRESS_RANGE_DESCRIPTOR;
typedef struct {
UINT64 InterruptedGuestVirtualAddress;
UINT32 Length;
UINT64 InterruptedCr3;
UINT64 InterruptedEptp;
UINT32 MapToSmmGuest:2;
UINT32 InterruptedCr4Pae:1;
UINT32 InterruptedCr4Pse:1;
UINT32 InterruptedIa32eMode:1;
UINT32 Reserved1:27;
UINT32 Reserved2;
UINT64 PhysicalAddress;
UINT64 SmmGuestVirtualAddress;
} STM_ADDRESS_LOOKUP_DESCRIPTOR;
#define DO_NOT_MAP 0
#define ONE_TO_ONE 1
#define VIRTUAL_ADDRESS_SPECIFIED 3
//
// STM_RESOURCE_LIST
//
#define END_OF_RESOURCES 0
#define MEM_RANGE 1
#define IO_RANGE 2
#define MMIO_RANGE 3
#define MACHINE_SPECIFIC_REG 4
#define PCI_CFG_RANGE 5
#define TRAPPED_IO_RANGE 6
#define ALL_RESOURCES 7
#define REGISTER_VIOLATION 8
#define MAX_DESC_TYPE 8
typedef struct {
UINT32 RscType;
UINT16 Length;
UINT16 ReturnStatus:1;
UINT16 Reserved:14;
UINT16 IgnoreResource:1;
} STM_RSC_DESC_HEADER;
typedef struct {
STM_RSC_DESC_HEADER Hdr;
UINT64 ResourceListContinuation;
} STM_RSC_END;
// byte granular Memory range support
#define STM_RSC_BGM 0x4
typedef struct {
STM_RSC_DESC_HEADER Hdr;
UINT64 Base;
UINT64 Length;
UINT32 RWXAttributes:3;
UINT32 Reserved:29;
UINT32 Reserved_2;
} STM_RSC_MEM_DESC;
#define STM_RSC_MEM_R 0x1
#define STM_RSC_MEM_W 0x2
#define STM_RSC_MEM_X 0x4
typedef struct {
STM_RSC_DESC_HEADER Hdr;
UINT16 Base;
UINT16 Length;
UINT32 Reserved;
} STM_RSC_IO_DESC;
// byte granular MMIO range support
#define STM_RSC_BGI 0x2
typedef struct {
STM_RSC_DESC_HEADER Hdr;
UINT64 Base;
UINT64 Length;
UINT32 RWXAttributes:3;
UINT32 Reserved:29;
UINT32 Reserved_2;
} STM_RSC_MMIO_DESC;
#define STM_RSC_MMIO_R 0x1
#define STM_RSC_MMIO_W 0x2
#define STM_RSC_MMIO_X 0x4
typedef struct {
STM_RSC_DESC_HEADER Hdr;
UINT32 MsrIndex;
UINT32 KernelModeProcessing:1;
UINT32 Reserved:31;
UINT64 ReadMask;
UINT64 WriteMask;
} STM_RSC_MSR_DESC;
// bit granular MSR resource support
#define STM_RSC_MSR 0x8
typedef struct {
UINT8 Type; // must be 1, indicating Hardware Device Path
UINT8 Subtype; // must be 1, indicating PCI
UINT16 Length; // sizeof(STM_PCI_DEVICE_PATH_NODE) which is 6
UINT8 PciFunction;
UINT8 PciDevice;
} STM_PCI_DEVICE_PATH_NODE;
typedef struct {
STM_RSC_DESC_HEADER Hdr;
UINT16 RWAttributes:2;
UINT16 Reserved:14;
UINT16 Base;
UINT16 Length;
UINT8 OriginatingBusNumber;
UINT8 LastNodeIndex;
STM_PCI_DEVICE_PATH_NODE PciDevicePath[1];
//STM_PCI_DEVICE_PATH_NODE PciDevicePath[LastNodeIndex + 1];
} STM_RSC_PCI_CFG_DESC;
#define STM_RSC_PCI_CFG_R 0x1
#define STM_RSC_PCI_CFG_W 0x2
typedef struct {
STM_RSC_DESC_HEADER Hdr;
UINT16 Base;
UINT16 Length;
UINT16 In:1;
UINT16 Out:1;
UINT16 Api:1;
UINT16 Reserved1:13;
UINT16 Reserved2;
} STM_RSC_TRAPPED_IO_DESC;
typedef struct {
STM_RSC_DESC_HEADER Hdr;
} STM_RSC_ALL_RESOURCES_DESC;
typedef struct {
STM_RSC_DESC_HEADER Hdr;
UINT32 RegisterType;
UINT32 Reserved;
UINT64 ReadMask;
UINT64 WriteMask;
} STM_REGISTER_VIOLATION_DESC;
typedef enum {
StmRegisterCr0,
StmRegisterCr2,
StmRegisterCr3,
StmRegisterCr4,
StmRegisterCr8,
StmRegisterMax,
} STM_REGISTER_VIOLATION_TYPE;
typedef union {
STM_RSC_DESC_HEADER Header;
STM_RSC_END End;
STM_RSC_MEM_DESC Mem;
STM_RSC_IO_DESC Io;
STM_RSC_MMIO_DESC Mmio;
STM_RSC_MSR_DESC Msr;
STM_RSC_PCI_CFG_DESC PciCfg;
STM_RSC_TRAPPED_IO_DESC TrappedIo;
STM_RSC_ALL_RESOURCES_DESC All;
STM_REGISTER_VIOLATION_DESC RegisterViolation;
} STM_RSC;
//
// VMCS database
//
#define STM_VMCS_DATABASE_REQUEST_ADD 1
#define STM_VMCS_DATABASE_REQUEST_REMOVE 0
// Values for DomainType
// Intepreter of DomainType
#define DOMAIN_DISALLOWED_IO_OUT (1u << 0)
#define DOMAIN_DISALLOWED_IO_IN (1u << 1)
#define DOMAIN_INTEGRITY (1u << 2)
#define DOMAIN_CONFIDENTIALITY (1u << 3)
#define DOMAIN_UNPROTECTED 0x00
#define DOMAIN_INTEGRITY_PROT_OUT_IN (DOMAIN_INTEGRITY)
//#define DOMAIN_INTEGRITY_PROT_OUT (DOMAIN_INTEGRITY | DOMAIN_DISALLOWED_IO_IN)
#define DOMAIN_FULLY_PROT_OUT_IN (DOMAIN_CONFIDENTIALITY | DOMAIN_INTEGRITY)
//#define DOMAIN_FULLY_PROT_IN (DOMAIN_CONFIDENTIALITY | DOMAIN_INTEGRITY | DOMAIN_DISALLOWED_IO_OUT)
//#define DOMAIN_FULLY_PROT_OUT (DOMAIN_CONFIDENTIALITY | DOMAIN_INTEGRITY | DOMAIN_DISALLOWED_IO_IN)
#define DOMAIN_FULLY_PROT (DOMAIN_CONFIDENTIALITY | DOMAIN_INTEGRITY | DOMAIN_DISALLOWED_IO_IN | DOMAIN_DISALLOWED_IO_OUT)
// Values for XStatePolicy
#define XSTATE_READWRITE 0x00
#define XSTATE_READONLY 0x01
#define XSTATE_SCRUB 0x03
typedef struct {
UINT64 VmcsPhysPointer; // bits 11:0 are reserved and must be 0
UINT32 DomainType :4;
UINT32 XStatePolicy :2;
UINT32 DegradationPolicy :4;
UINT32 Reserved1 :22; // Must be 0
UINT32 AddOrRemove;
} STM_VMCS_DATABASE_REQUEST;
//
// Event log
//
#define NEW_LOG 1
#define CONFIGURE_LOG 2
#define START_LOG 3
#define STOP_LOG 4
#define CLEAR_LOG 5
#define DELETE_LOG 6
typedef enum {
EvtLogStarted,
EvtLogStopped,
EvtLogInvalidParameterDetected,
EvtHandledProtectionException,
// unhandled protection exceptions result in reset & cannot be logged
EvtBiosAccessToUnclaimedResource,
EvtMleResourceProtectionGranted,
EvtMleResourceProtectionDenied,
EvtMleResourceUnprotect,
EvtMleResourceUnprotectError,
EvtMleDomainTypeDegraded,
// add more here
EvtMleMax,
// Not used
EvtInvalid = 0xFFFFFFFF,
} EVENT_TYPE;
//#define STM_EVENT_LOG_PAGE_COUNT_MAX 62
typedef struct {
UINT32 PageCount;
UINT64 Pages[1]; // number of elements is PageCount
} STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA_LOG_BUFFER;
typedef union {
STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA_LOG_BUFFER LogBuffer;
UINT32 EventEnableBitmap; // bitmap of EVENT_TYPE
} STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA;
typedef struct {
UINT32 SubFunctionIndex;
STM_EVENT_LOG_MANAGEMENT_REQUEST_DATA Data;
} STM_EVENT_LOG_MANAGEMENT_REQUEST;
//
// VMCALL API Numbers
//
// API number convention: BIOS facing VMCALL interfaces have bit 16 clear
#define STM_API_MAP_ADDRESS_RANGE 0x00000001
#define STM_API_UNMAP_ADDRESS_RANGE 0x00000002
#define STM_API_ADDRESS_LOOKUP 0x00000003
#define STM_API_RETURN_FROM_PROTECTION_EXCEPTION 0x00000004
// API number convention: MLE facing VMCALL interfaces have bit 16 set
//
// The STM configuration lifecycle is as follows:
// 1. SENTER->SINIT->MLE: MLE begins execution with SMI disabled (masked).
// 2. MLE invokes InitializeProtectionVMCALL() to prepare STM for setup of initial protection profile. This is done on a single CPU and has global effect.
// 3. MLE invokes ProtectResourceVMCALL() to define the initial protection profile. The protection profile is global across all CPUs.
// 4. MLE invokes StartStmVMCALL() to enable the STM to begin receiving SMI events. This must be done on every logical CPU.
// 5. MLE may invoke ProtectResourceVMCALL() or UnProtectResourceVMCALL() during runtime as many times as necessary.
// 6. MLE invokes StopStmVMCALL() to disable the STM. SMI is again masked following StopStmVMCALL().
//
#define STM_API_START 0x00010001
#define STM_API_STOP 0x00010002
#define STM_API_PROTECT_RESOURCE 0x00010003
#define STM_API_UNPROTECT_RESOURCE 0x00010004
#define STM_API_GET_BIOS_RESOURCES 0x00010005
#define STM_API_MANAGE_VMCS_DATABASE 0x00010006
#define STM_API_INITIALIZE_PROTECTION 0x00010007
#define STM_API_MANAGE_EVENT_LOG 0x00010008
//
// Return codes
//
typedef UINT32 STM_STATUS;
#define STM_SUCCESS 0x00000000
#define SMM_SUCCESS 0x00000000
// all error codes have bit 31 set
// STM errors have bit 16 set
#define ERROR_STM_SECURITY_VIOLATION 0x80010001
#define ERROR_STM_CACHE_TYPE_NOT_SUPPORTED 0x80010002
#define ERROR_STM_PAGE_NOT_FOUND 0x80010003
#define ERROR_STM_BAD_CR3 0x80010004
#define ERROR_STM_PHYSICAL_OVER_4G 0x80010005
#define ERROR_STM_VIRTUAL_SPACE_TOO_SMALL 0x80010006
#define ERROR_STM_UNPROTECTABLE_RESOURCE 0x80010007
#define ERROR_STM_ALREADY_STARTED 0x80010008
#define ERROR_STM_WITHOUT_SMX_UNSUPPORTED 0x80010009
#define ERROR_STM_STOPPED 0x8001000A
#define ERROR_STM_BUFFER_TOO_SMALL 0x8001000B
#define ERROR_STM_INVALID_VMCS_DATABASE 0x8001000C
#define ERROR_STM_MALFORMED_RESOURCE_LIST 0x8001000D
#define ERROR_STM_INVALID_PAGECOUNT 0x8001000E
#define ERROR_STM_LOG_ALLOCATED 0x8001000F
#define ERROR_STM_LOG_NOT_ALLOCATED 0x80010010
#define ERROR_STM_LOG_NOT_STOPPED 0x80010011
#define ERROR_STM_LOG_NOT_STARTED 0x80010012
#define ERROR_STM_RESERVED_BIT_SET 0x80010013
#define ERROR_STM_NO_EVENTS_ENABLED 0x80010014
#define ERROR_STM_OUT_OF_RESOURCES 0x80010015
#define ERROR_STM_FUNCTION_NOT_SUPPORTED 0x80010016
#define ERROR_STM_UNPROTECTABLE 0x80010017
#define ERROR_STM_UNSUPPORTED_MSR_BIT 0x80010018
#define ERROR_STM_UNSPECIFIED 0x8001FFFF
// SMM errors have bit 17 set
#define ERROR_SMM_BAD_BUFFER 0x80020001
#define ERROR_SMM_INVALID_RSC 0x80020004
#define ERROR_SMM_INVALID_BUFFER_SIZE 0x80020005
#define ERROR_SMM_BUFFER_TOO_SHORT 0x80020006
#define ERROR_SMM_INVALID_LIST 0x80020007
#define ERROR_SMM_OUT_OF_MEMORY 0x80020008
#define ERROR_SMM_AFTER_INIT 0x80020009
#define ERROR_SMM_UNSPECIFIED 0x8002FFFF
// Errors that apply to both have bits 15, 16, and 17 set
#define ERROR_INVALID_API 0x80038001
#define ERROR_INVALID_PARAMETER 0x80038002
//
// STM TXT.ERRORCODE codes
//
#define STM_CRASH_PROTECTION_EXCEPTION 0xC000F001
#define STM_CRASH_PROTECTION_EXCEPTION_FAILURE 0xC000F002
#define STM_CRASH_DOMAIN_DEGRADATION_FAILURE 0xC000F003
#define STM_CRASH_BIOS_PANIC 0xC000E000
typedef struct {
UINT32 EventSerialNumber;
UINT16 Type;
UINT16 Lock :1;
UINT16 Valid :1;
UINT16 ReadByMle :1;
UINT16 Wrapped :1;
UINT16 Reserved :12;
} LOG_ENTRY_HEADER;
typedef struct {
UINT32 Reserved;
} ENTRY_EVT_LOG_STARTED;
typedef struct {
UINT32 Reserved;
} ENTRY_EVT_LOG_STOPPED;
typedef struct {
UINT32 VmcallApiNumber;
} ENTRY_EVT_LOG_INVALID_PARAM;
typedef struct {
STM_RSC Resource;
} ENTRY_EVT_LOG_HANDLED_PROTECTION_EXCEPTION;
typedef struct {
STM_RSC Resource;
} ENTRY_EVT_BIOS_ACCESS_UNCLAIMED_RSC;
typedef struct {
STM_RSC Resource;
} ENTRY_EVT_MLE_RSC_PROT_GRANTED;
typedef struct {
STM_RSC Resource;
} ENTRY_EVT_MLE_RSC_PROT_DENIED;
typedef struct {
STM_RSC Resource;
} ENTRY_EVT_MLE_RSC_UNPROT;
typedef struct {
STM_RSC Resource;
} ENTRY_EVT_MLE_RSC_UNPROT_ERROR;
typedef struct {
UINT64 VmcsPhysPointer;
UINT8 ExpectedDomainType;
UINT8 DegradedDomainType;
} ENTRY_EVT_MLE_DOMAIN_TYPE_DEGRADED;
typedef union {
ENTRY_EVT_LOG_STARTED Started;
ENTRY_EVT_LOG_STOPPED Stopped;
ENTRY_EVT_LOG_INVALID_PARAM InvalidParam;
ENTRY_EVT_LOG_HANDLED_PROTECTION_EXCEPTION HandledProtectionException;
ENTRY_EVT_BIOS_ACCESS_UNCLAIMED_RSC BiosUnclaimedRsc;
ENTRY_EVT_MLE_RSC_PROT_GRANTED MleRscProtGranted;
ENTRY_EVT_MLE_RSC_PROT_DENIED MleRscProtDenied;
ENTRY_EVT_MLE_RSC_UNPROT MleRscUnprot;
ENTRY_EVT_MLE_RSC_UNPROT_ERROR MleRscUnprotError;
ENTRY_EVT_MLE_DOMAIN_TYPE_DEGRADED MleDomainTypeDegraded;
} LOG_ENTRY_DATA;
typedef struct {
LOG_ENTRY_HEADER Hdr;
LOG_ENTRY_DATA Data;
} STM_LOG_ENTRY;
#define STM_LOG_ENTRY_SIZE 256
//
//
//
#define STM_CONFIG_SMI_UNBLOCKING_BY_VMX_OFF 0x1
//
// TXT debug
//
#define SW_SMI_STM_ADD_RUNTIME_RESOURCES_SUB_FUNC 0
#define SW_SMI_STM_READ_BIOS_RESOURCES_SUB_FUNC 1
#define SW_SMI_STM_REPLACE_BIOS_RESOURCES_SUB_FUNC 2
typedef struct {
UINT32 BufferSize;
UINT32 Reserved;
//UINT8 Data[];
} TXT_BIOS_DEBUG;
#pragma pack (pop)
#endif

View File

@ -0,0 +1,676 @@
/** @file
The CPU specific programming for PiSmmCpuDxeSmm module.
Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiSmm.h>
#include <Library/SmmCpuFeaturesLib.h>
#include <Library/BaseLib.h>
#include <Library/MtrrLib.h>
#include <Library/PcdLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Register/Cpuid.h>
#include <Register/SmramSaveStateMap.h>
//
// Machine Specific Registers (MSRs)
//
#define SMM_FEATURES_LIB_IA32_MTRR_CAP 0x0FE
#define SMM_FEATURES_LIB_IA32_FEATURE_CONTROL 0x03A
#define SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE 0x1F2
#define SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK 0x1F3
#define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE 0x0A0
#define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK 0x0A1
#define EFI_MSR_SMRR_MASK 0xFFFFF000
#define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11
#define SMM_FEATURES_LIB_SMM_FEATURE_CONTROL 0x4E0
//
// MSRs required for configuration of SMM Code Access Check
//
#define SMM_FEATURES_LIB_IA32_MCA_CAP 0x17D
#define SMM_CODE_ACCESS_CHK_BIT BIT58
//
// Set default value to assume SMRR is not supported
//
BOOLEAN mSmrrSupported = FALSE;
//
// Set default value to assume MSR_SMM_FEATURE_CONTROL is not supported
//
BOOLEAN mSmmFeatureControlSupported = FALSE;
//
// Set default value to assume IA-32 Architectural MSRs are used
//
UINT32 mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE;
UINT32 mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK;
//
// Set default value to assume MTRRs need to be configured on each SMI
//
BOOLEAN mNeedConfigureMtrrs = TRUE;
//
// Array for state of SMRR enable on all CPUs
//
BOOLEAN *mSmrrEnabled;
/**
The constructor function
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
**/
EFI_STATUS
EFIAPI
SmmCpuFeaturesLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT32 RegEax;
UINT32 RegEdx;
UINTN FamilyId;
UINTN ModelId;
//
// Retrieve CPU Family and Model
//
AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx);
FamilyId = (RegEax >> 8) & 0xf;
ModelId = (RegEax >> 4) & 0xf;
if (FamilyId == 0x06 || FamilyId == 0x0f) {
ModelId = ModelId | ((RegEax >> 12) & 0xf0);
}
//
// Check CPUID(CPUID_VERSION_INFO).EDX[12] for MTRR capability
//
if ((RegEdx & BIT12) != 0) {
//
// Check MTRR_CAP MSR bit 11 for SMRR support
//
if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MTRR_CAP) & BIT11) != 0) {
mSmrrSupported = TRUE;
}
}
//
// Intel(R) 64 and IA-32 Architectures Software Developer's Manual
// Volume 3C, Section 35.3 MSRs in the Intel(R) Atom(TM) Processor Family
//
// If CPU Family/Model is 06_1CH, 06_26H, 06_27H, 06_35H or 06_36H, then
// SMRR Physical Base and SMM Physical Mask MSRs are not available.
//
if (FamilyId == 0x06) {
if (ModelId == 0x1C || ModelId == 0x26 || ModelId == 0x27 || ModelId == 0x35 || ModelId == 0x36) {
mSmrrSupported = FALSE;
}
}
//
// Intel(R) 64 and IA-32 Architectures Software Developer's Manual
// Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family
//
// If CPU Family/Model is 06_0F or 06_17, then use Intel(R) Core(TM) 2
// Processor Family MSRs
//
if (FamilyId == 0x06) {
if (ModelId == 0x17 || ModelId == 0x0f) {
mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE;
mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK;
}
}
//
// Intel(R) 64 and IA-32 Architectures Software Developer's Manual
// Volume 3C, Section 34.4.2 SMRAM Caching
// An IA-32 processor does not automatically write back and invalidate its
// caches before entering SMM or before exiting SMM. Because of this behavior,
// care must be taken in the placement of the SMRAM in system memory and in
// the caching of the SMRAM to prevent cache incoherence when switching back
// and forth between SMM and protected mode operation.
//
// An IA-32 processor is a processor that does not support the Intel 64
// Architecture. Support for the Intel 64 Architecture can be detected from
// CPUID(CPUID_EXTENDED_CPU_SIG).EDX[29]
//
// If an IA-32 processor is detected, then set mNeedConfigureMtrrs to TRUE,
// so caches are flushed on SMI entry and SMI exit, the interrupted code
// MTRRs are saved/restored, and MTRRs for SMM are loaded.
//
AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
if (RegEax >= CPUID_EXTENDED_CPU_SIG) {
AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
if ((RegEdx & BIT29) != 0) {
mNeedConfigureMtrrs = FALSE;
}
}
//
// Allocate array for state of SMRR enable on all CPUs
//
mSmrrEnabled = (BOOLEAN *)AllocatePool (sizeof (BOOLEAN) * PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
ASSERT (mSmrrEnabled != NULL);
return EFI_SUCCESS;
}
/**
Called during the very first SMI into System Management Mode to initialize
CPU features, including SMBASE, for the currently executing CPU. Since this
is the first SMI, the SMRAM Save State Map is at the default address of
SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing
CPU is specified by CpuIndex and CpuIndex can be used to access information
about the currently executing CPU in the ProcessorInfo array and the
HotPlugCpuData data structure.
@param[in] CpuIndex The index of the CPU to initialize. The value
must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that
was elected as monarch during System Management
Mode initialization.
FALSE if the CpuIndex is not the index of the CPU
that was elected as monarch during System
Management Mode initialization.
@param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION
structures. ProcessorInfo[CpuIndex] contains the
information for the currently executing CPU.
@param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that
contains the ApidId and SmBase arrays.
**/
VOID
EFIAPI
SmmCpuFeaturesInitializeProcessor (
IN UINTN CpuIndex,
IN BOOLEAN IsMonarch,
IN EFI_PROCESSOR_INFORMATION *ProcessorInfo,
IN CPU_HOT_PLUG_DATA *CpuHotPlugData
)
{
SMRAM_SAVE_STATE_MAP *CpuState;
UINT64 FeatureControl;
UINT32 RegEax;
UINT32 RegEdx;
UINTN FamilyId;
UINTN ModelId;
//
// Configure SMBASE.
//
CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];
//
// Intel(R) 64 and IA-32 Architectures Software Developer's Manual
// Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family
//
// If Intel(R) Core(TM) Core(TM) 2 Processor Family MSRs are being used, then
// make sure SMRR Enable(BIT3) of MSR_FEATURE_CONTROL MSR(0x3A) is set before
// accessing SMRR base/mask MSRs. If Lock(BIT0) of MSR_FEATURE_CONTROL MSR(0x3A)
// is set, then the MSR is locked and can not be modified.
//
if (mSmrrSupported && mSmrrPhysBaseMsr == SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE) {
FeatureControl = AsmReadMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL);
if ((FeatureControl & BIT3) == 0) {
if ((FeatureControl & BIT0) == 0) {
AsmWriteMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL, FeatureControl | BIT3);
} else {
mSmrrSupported = FALSE;
}
}
}
//
// If SMRR is supported, then program SMRR base/mask MSRs.
// The EFI_MSR_SMRR_PHYS_MASK_VALID bit is not set until the first normal SMI.
// The code that initializes SMM environment is running in normal mode
// from SMRAM region. If SMRR is enabled here, then the SMRAM region
// is protected and the normal mode code execution will fail.
//
if (mSmrrSupported) {
AsmWriteMsr64 (mSmrrPhysBaseMsr, CpuHotPlugData->SmrrBase | MTRR_CACHE_WRITE_BACK);
AsmWriteMsr64 (mSmrrPhysMaskMsr, (~(CpuHotPlugData->SmrrSize - 1) & EFI_MSR_SMRR_MASK));
mSmrrEnabled[CpuIndex] = FALSE;
}
//
// Retrieve CPU Family and Model
//
AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx);
FamilyId = (RegEax >> 8) & 0xf;
ModelId = (RegEax >> 4) & 0xf;
if (FamilyId == 0x06 || FamilyId == 0x0f) {
ModelId = ModelId | ((RegEax >> 12) & 0xf0);
}
//
// Intel(R) 64 and IA-32 Architectures Software Developer's Manual
// Volume 3C, Section 35.10.1 MSRs in 4th Generation Intel(R) Core(TM)
// Processor Family.
//
// If CPU Family/Model is 06_3C, 06_45, or 06_46 then use 4th Generation
// Intel(R) Core(TM) Processor Family MSRs.
//
if (FamilyId == 0x06) {
if (ModelId == 0x3C || ModelId == 0x45 || ModelId == 0x46) {
//
// Check to see if the CPU supports the SMM Code Access Check feature
// Do not access this MSR unless the CPU supports the SmmRegFeatureControl
//
if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) != 0) {
mSmmFeatureControlSupported = TRUE;
}
}
}
}
/**
This function updates the SMRAM save state on the currently executing CPU
to resume execution at a specific address after an RSM instruction. This
function must evaluate the SMRAM save state to determine the execution mode
the RSM instruction resumes and update the resume execution address with
either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart
flag in the SMRAM save state must always be cleared. This function returns
the value of the instruction pointer from the SMRAM save state that was
replaced. If this function returns 0, then the SMRAM save state was not
modified.
This function is called during the very first SMI on each CPU after
SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
to signal that the SMBASE of each CPU has been updated before the default
SMBASE address is used for the first SMI to the next CPU.
@param[in] CpuIndex The index of the CPU to hook. The value
must be between 0 and the NumberOfCpus
field in the System Management System Table
(SMST).
@param[in] CpuState Pointer to SMRAM Save State Map for the
currently executing CPU.
@param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
32-bit execution mode from 64-bit SMM.
@param[in] NewInstructionPointer Instruction pointer to use if resuming to
same execution mode as SMM.
@retval 0 This function did modify the SMRAM save state.
@retval > 0 The original instruction pointer value from the SMRAM save state
before it was replaced.
**/
UINT64
EFIAPI
SmmCpuFeaturesHookReturnFromSmm (
IN UINTN CpuIndex,
IN SMRAM_SAVE_STATE_MAP *CpuState,
IN UINT64 NewInstructionPointer32,
IN UINT64 NewInstructionPointer
)
{
return 0;
}
/**
Hook point in normal execution mode that allows the one CPU that was elected
as monarch during System Management Mode initialization to perform additional
initialization actions immediately after all of the CPUs have processed their
first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
**/
VOID
EFIAPI
SmmCpuFeaturesSmmRelocationComplete (
VOID
)
{
}
/**
Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
returned, then a custom SMI handler is not provided by this library,
and the default SMI handler must be used.
@retval 0 Use the default SMI handler.
@retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
The caller is required to allocate enough SMRAM for each CPU to
support the size of the custom SMI handler.
**/
UINTN
EFIAPI
SmmCpuFeaturesGetSmiHandlerSize (
VOID
)
{
return 0;
}
/**
Return the offset to SMBASE, of a custom native SMI Handler in bytes.
If 0 is returned, then a custom SMI handler is not provided by this library,
and the default SMI handler must be used.
@retval 0 Use the default SMI handler.
@retval > 0 If STM is enabled, TXT_PROCESSOR_SMM_DESCRIPTOR.SmmSmiHandlerRip
is SmiHandlerOffset + SMBASE.
**/
UINTN
EFIAPI
SmmCpuFeaturesGetSmiHandlerOffset (
VOID
)
{
return 0;
}
/**
Install a custom SMI handler for the CPU specified by CpuIndex. This function
is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
than zero and is called by the CPU that was elected as monarch during System
Management Mode initialization.
@param[in] CpuIndex The index of the CPU to install the custom SMI handler.
The value must be between 0 and the NumberOfCpus field
in the System Management System Table (SMST).
@param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
@param[in] SmiStack The stack to use when an SMI is processed by the
the CPU specified by CpuIndex.
@param[in] StackSize The size, in bytes, if the stack used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtBase The base address of the GDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtBase The base address of the IDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] Cr3 The base address of the page tables to use when an SMI
is processed by the CPU specified by CpuIndex.
**/
VOID
EFIAPI
SmmCpuFeaturesInstallSmiHandler (
IN UINTN CpuIndex,
IN UINT32 SmBase,
IN VOID *SmiStack,
IN UINTN StackSize,
IN UINTN GdtBase,
IN UINTN GdtSize,
IN UINTN IdtBase,
IN UINTN IdtSize,
IN UINT32 Cr3
)
{
}
/**
Determines if MTRR registers must be configured to set SMRAM cache-ability
when executing in System Management Mode.
@retval TRUE MTRR registers must be configured to set SMRAM cache-ability.
@retval FALSE MTRR registers do not need to be configured to set SMRAM
cache-ability.
**/
BOOLEAN
EFIAPI
SmmCpuFeaturesNeedConfigureMtrrs (
VOID
)
{
return mNeedConfigureMtrrs;
}
/**
Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
returns TRUE.
**/
VOID
EFIAPI
SmmCpuFeaturesDisableSmrr (
VOID
)
{
if (mSmrrSupported && mNeedConfigureMtrrs) {
AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64(mSmrrPhysMaskMsr) & ~EFI_MSR_SMRR_PHYS_MASK_VALID);
}
}
/**
Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
returns TRUE.
**/
VOID
EFIAPI
SmmCpuFeaturesReenableSmrr (
VOID
)
{
if (mSmrrSupported && mNeedConfigureMtrrs) {
AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64(mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID);
}
}
/**
Processor specific hook point each time a CPU enters System Management Mode.
@param[in] CpuIndex The index of the CPU that has entered SMM. The value
must be between 0 and the NumberOfCpus field in the
System Management System Table (SMST).
**/
VOID
EFIAPI
SmmCpuFeaturesRendezvousEntry (
IN UINTN CpuIndex
)
{
//
// If SMRR is supported and this is the first normal SMI, then enable SMRR
//
if (mSmrrSupported && !mSmrrEnabled[CpuIndex]) {
AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64 (mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID);
mSmrrEnabled[CpuIndex] = TRUE;
}
}
/**
Processor specific hook point each time a CPU exits System Management Mode.
@param[in] CpuIndex The index of the CPU that is exiting SMM. The value must
be between 0 and the NumberOfCpus field in the System
Management System Table (SMST).
**/
VOID
EFIAPI
SmmCpuFeaturesRendezvousExit (
IN UINTN CpuIndex
)
{
}
/**
Check to see if an SMM register is supported by a specified CPU.
@param[in] CpuIndex The index of the CPU to check for SMM register support.
The value must be between 0 and the NumberOfCpus field
in the System Management System Table (SMST).
@param[in] RegName Identifies the SMM register to check for support.
@retval TRUE The SMM register specified by RegName is supported by the CPU
specified by CpuIndex.
@retval FALSE The SMM register specified by RegName is not supported by the
CPU specified by CpuIndex.
**/
BOOLEAN
EFIAPI
SmmCpuFeaturesIsSmmRegisterSupported (
IN UINTN CpuIndex,
IN SMM_REG_NAME RegName
)
{
if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) {
return TRUE;
}
return FALSE;
}
/**
Returns the current value of the SMM register for the specified CPU.
If the SMM register is not supported, then 0 is returned.
@param[in] CpuIndex The index of the CPU to read the SMM register. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] RegName Identifies the SMM register to read.
@return The value of the SMM register specified by RegName from the CPU
specified by CpuIndex.
**/
UINT64
EFIAPI
SmmCpuFeaturesGetSmmRegister (
IN UINTN CpuIndex,
IN SMM_REG_NAME RegName
)
{
if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) {
return AsmReadMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL);
}
return 0;
}
/**
Sets the value of an SMM register on a specified CPU.
If the SMM register is not supported, then no action is performed.
@param[in] CpuIndex The index of the CPU to write the SMM register. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] RegName Identifies the SMM register to write.
registers are read-only.
@param[in] Value The value to write to the SMM register.
**/
VOID
EFIAPI
SmmCpuFeaturesSetSmmRegister (
IN UINTN CpuIndex,
IN SMM_REG_NAME RegName,
IN UINT64 Value
)
{
if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) {
AsmWriteMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL, Value);
}
}
/**
Read an SMM Save State register on the target processor. If this function
returns EFI_UNSUPPORTED, then the caller is responsible for reading the
SMM Save Sate register.
@param[in] CpuIndex The index of the CPU to read the SMM Save State. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] Register The SMM Save State register to read.
@param[in] Width The number of bytes to read from the CPU save state.
@param[out] Buffer Upon return, this holds the CPU register value read
from the save state.
@retval EFI_SUCCESS The register was read from Save State.
@retval EFI_INVALID_PARAMTER Buffer is NULL.
@retval EFI_UNSUPPORTED This function does not support reading Register.
**/
EFI_STATUS
EFIAPI
SmmCpuFeaturesReadSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
OUT VOID *Buffer
)
{
return EFI_UNSUPPORTED;
}
/**
Writes an SMM Save State register on the target processor. If this function
returns EFI_UNSUPPORTED, then the caller is responsible for writing the
SMM Save Sate register.
@param[in] CpuIndex The index of the CPU to write the SMM Save State. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] Register The SMM Save State register to write.
@param[in] Width The number of bytes to write to the CPU save state.
@param[in] Buffer Upon entry, this holds the new CPU register value.
@retval EFI_SUCCESS The register was written to Save State.
@retval EFI_INVALID_PARAMTER Buffer is NULL.
@retval EFI_UNSUPPORTED This function does not support writing Register.
**/
EFI_STATUS
EFIAPI
SmmCpuFeaturesWriteSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
IN CONST VOID *Buffer
)
{
return EFI_UNSUPPORTED;
}
/**
This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
notification is completely processed.
**/
VOID
EFIAPI
SmmCpuFeaturesCompleteSmmReadyToLock (
VOID
)
{
}
/**
This API provides a method for a CPU to allocate a specific region for storing page tables.
This API can be called more once to allocate memory for page tables.
Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
is returned. If there is not enough memory remaining to satisfy the request, then NULL is
returned.
This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM.
@param Pages The number of 4 KB pages to allocate.
@return A pointer to the allocated buffer for page tables.
@retval NULL Fail to allocate a specific region for storing page tables,
Or there is no preference on where the page tables are allocated in SMRAM.
**/
VOID *
EFIAPI
SmmCpuFeaturesAllocatePageTableMemory (
IN UINTN Pages
)
{
return NULL;
}

View File

@ -0,0 +1,40 @@
## @file
# The CPU specific programming for PiSmmCpuDxeSmm module.
#
# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SmmCpuFeaturesLib
MODULE_UNI_FILE = SmmCpuFeaturesLib.uni
FILE_GUID = FC3DC10D-D271-422a-AFF3-CBCF70344431
MODULE_TYPE = DXE_SMM_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = SmmCpuFeaturesLib
CONSTRUCTOR = SmmCpuFeaturesLibConstructor
[Sources]
SmmCpuFeaturesLib.c
[Packages]
MdePkg/MdePkg.dec
StmCpuPkg/StmCpuPkg.dec
UefiCpuPkg/UefiCpuPkg.dec
[LibraryClasses]
BaseLib
PcdLib
MemoryAllocationLib
DebugLib
[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## SOMETIMES_CONSUMES

View File

@ -0,0 +1,18 @@
// /** @file
// The CPU specific programming for PiSmmCpuDxeSmm module.
//
// Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
//
// This program and the accompanying materials
// are licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module."
#string STR_MODULE_DESCRIPTION #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module."

View File

@ -0,0 +1,108 @@
/** @file
SMM CPU Platform Hook NULL library instance.
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiSmm.h>
#include <Library/SmmCpuPlatformHookLib.h>
/**
Checks if platform produces a valid SMI.
This function checks if platform produces a valid SMI. This function is
called at SMM entry to detect if this is a spurious SMI. This function
must be implemented in an MP safe way because it is called by multiple CPU
threads.
@retval TRUE There is a valid SMI
@retval FALSE There is no valid SMI
**/
BOOLEAN
EFIAPI
PlatformValidSmi (
VOID
)
{
return TRUE;
}
/**
Clears platform top level SMI status bit.
This function clears platform top level SMI status bit.
@retval TRUE The platform top level SMI status is cleared.
@retval FALSE The platform top level SMI status cannot be cleared.
**/
BOOLEAN
EFIAPI
ClearTopLevelSmiStatus (
VOID
)
{
return TRUE;
}
/**
Performs platform specific way of SMM BSP election.
This function performs platform specific way of SMM BSP election.
@param IsBsp Output parameter. TRUE: the CPU this function executes
on is elected to be the SMM BSP. FALSE: the CPU this
function executes on is to be SMM AP.
@retval EFI_SUCCESS The function executes successfully.
@retval EFI_NOT_READY The function does not determine whether this CPU should be
BSP or AP. This may occur if hardware init sequence to
enable the determination is yet to be done, or the function
chooses not to do BSP election and will let SMM CPU driver to
use its default BSP election process.
@retval EFI_DEVICE_ERROR The function cannot determine whether this CPU should be
BSP or AP due to hardware error.
**/
EFI_STATUS
EFIAPI
PlatformSmmBspElection (
OUT BOOLEAN *IsBsp
)
{
return EFI_NOT_READY;
}
/**
Get platform page table attribute.
This function gets page table attribute of platform.
@param Address Input parameter. Obtain the page table entries attribute on this address.
@param PageSize Output parameter. The size of the page.
@param NumOfPages Output parameter. Number of page.
@param PageAttribute Output parameter. Paging Attributes (WB, UC, etc).
@retval EFI_SUCCESS The platform page table attribute from the address is determined.
@retval EFI_UNSUPPORTED The platform does not support getting page table attribute for the address.
**/
EFI_STATUS
EFIAPI
GetPlatformPageTableAttribute (
IN UINT64 Address,
IN OUT SMM_PAGE_SIZE_TYPE *PageSize,
IN OUT UINTN *NumOfPages,
IN OUT UINTN *PageAttribute
)
{
return EFI_UNSUPPORTED;
}

View File

@ -0,0 +1,41 @@
## @file
# SMM CPU Platform Hook NULL library instance.
#
# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
################################################################################
#
# Defines Section - statements that will be processed to create a Makefile.
#
################################################################################
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SmmCpuPlatformHookLibNull
MODULE_UNI_FILE = SmmCpuPlatformHookLibNull.uni
FILE_GUID = D6494E1B-E06F-4ab5-B64D-48B25AA9EB33
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = SmmCpuPlatformHookLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
SmmCpuPlatformHookLibNull.c
[Packages]
MdePkg/MdePkg.dec
StmCpuPkg/StmCpuPkg.dec
UefiCpuPkg/UefiCpuPkg.dec

View File

@ -0,0 +1,18 @@
// /** @file
// SMM CPU Platform Hook NULL library instance.
//
// Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
//
// This program and the accompanying materials
// are licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "SMM CPU Platform Hook NULL library instance"
#string STR_MODULE_DESCRIPTION #language en-US "SMM CPU Platform Hook NULL library instance."

View File

@ -0,0 +1,491 @@
/** @file
Code for Processor S3 restoration
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
typedef struct {
UINTN Lock;
VOID *StackStart;
UINTN StackSize;
VOID *ApFunction;
IA32_DESCRIPTOR GdtrProfile;
IA32_DESCRIPTOR IdtrProfile;
UINT32 BufferStart;
UINT32 Cr3;
} MP_CPU_EXCHANGE_INFO;
typedef struct {
UINT8 *RendezvousFunnelAddress;
UINTN PModeEntryOffset;
UINTN FlatJumpOffset;
UINTN Size;
UINTN LModeEntryOffset;
UINTN LongJumpOffset;
} MP_ASSEMBLY_ADDRESS_MAP;
/**
Get starting address and size of the rendezvous entry for APs.
Information for fixing a jump instruction in the code is also returned.
@param AddressMap Output buffer for address map information.
**/
VOID *
EFIAPI
AsmGetAddressMap (
MP_ASSEMBLY_ADDRESS_MAP *AddressMap
);
#define LEGACY_REGION_SIZE (2 * 0x1000)
#define LEGACY_REGION_BASE (0xA0000 - LEGACY_REGION_SIZE)
#define MSR_SPIN_LOCK_INIT_NUM 15
ACPI_CPU_DATA mAcpiCpuData;
UINT32 mNumberToFinish;
MP_CPU_EXCHANGE_INFO *mExchangeInfo;
BOOLEAN mRestoreSmmConfigurationInS3 = FALSE;
VOID *mGdtForAp = NULL;
VOID *mIdtForAp = NULL;
VOID *mMachineCheckHandlerForAp = NULL;
MP_MSR_LOCK *mMsrSpinLocks = NULL;
UINTN mMsrSpinLockCount = MSR_SPIN_LOCK_INIT_NUM;
UINTN mMsrCount = 0;
/**
Get MSR spin lock by MSR index.
@param MsrIndex MSR index value.
@return Pointer to MSR spin lock.
**/
SPIN_LOCK *
GetMsrSpinLockByIndex (
IN UINT32 MsrIndex
)
{
UINTN Index;
for (Index = 0; Index < mMsrCount; Index++) {
if (MsrIndex == mMsrSpinLocks[Index].MsrIndex) {
return &mMsrSpinLocks[Index].SpinLock;
}
}
return NULL;
}
/**
Initialize MSR spin lock by MSR index.
@param MsrIndex MSR index value.
**/
VOID
InitMsrSpinLockByIndex (
IN UINT32 MsrIndex
)
{
UINTN NewMsrSpinLockCount;
if (mMsrSpinLocks == NULL) {
mMsrSpinLocks = (MP_MSR_LOCK *) AllocatePool (sizeof (MP_MSR_LOCK) * mMsrSpinLockCount);
ASSERT (mMsrSpinLocks != NULL);
}
if (GetMsrSpinLockByIndex (MsrIndex) == NULL) {
//
// Initialize spin lock for MSR programming
//
mMsrSpinLocks[mMsrCount].MsrIndex = MsrIndex;
InitializeSpinLock (&mMsrSpinLocks[mMsrCount].SpinLock);
mMsrCount ++;
if (mMsrCount == mMsrSpinLockCount) {
//
// If MSR spin lock buffer is full, enlarge it
//
NewMsrSpinLockCount = mMsrSpinLockCount + MSR_SPIN_LOCK_INIT_NUM;
mMsrSpinLocks = ReallocatePool (
sizeof (MP_MSR_LOCK) * mMsrSpinLockCount,
sizeof (MP_MSR_LOCK) * NewMsrSpinLockCount,
mMsrSpinLocks
);
mMsrSpinLockCount = NewMsrSpinLockCount;
}
}
}
/**
Sync up the MTRR values for all processors.
@param MtrrTable Table holding fixed/variable MTRR values to be loaded.
**/
VOID
EFIAPI
LoadMtrrData (
EFI_PHYSICAL_ADDRESS MtrrTable
)
/*++
Routine Description:
Sync up the MTRR values for all processors.
Arguments:
Returns:
None
--*/
{
MTRR_SETTINGS *MtrrSettings;
MtrrSettings = (MTRR_SETTINGS *) (UINTN) MtrrTable;
MtrrSetAllMtrrs (MtrrSettings);
}
/**
Programs registers for the calling processor.
This function programs registers for the calling processor.
@param RegisterTable Pointer to register table of the running processor.
**/
VOID
SetProcessorRegister (
IN CPU_REGISTER_TABLE *RegisterTable
)
{
CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
UINTN Index;
UINTN Value;
SPIN_LOCK *MsrSpinLock;
//
// Traverse Register Table of this logical processor
//
RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
for (Index = 0; Index < RegisterTable->TableLength; Index++, RegisterTableEntry++) {
//
// Check the type of specified register
//
switch (RegisterTableEntry->RegisterType) {
//
// The specified register is Control Register
//
case ControlRegister:
switch (RegisterTableEntry->Index) {
case 0:
Value = AsmReadCr0 ();
Value = (UINTN) BitFieldWrite64 (
Value,
RegisterTableEntry->ValidBitStart,
RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
(UINTN) RegisterTableEntry->Value
);
AsmWriteCr0 (Value);
break;
case 2:
Value = AsmReadCr2 ();
Value = (UINTN) BitFieldWrite64 (
Value,
RegisterTableEntry->ValidBitStart,
RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
(UINTN) RegisterTableEntry->Value
);
AsmWriteCr2 (Value);
break;
case 3:
Value = AsmReadCr3 ();
Value = (UINTN) BitFieldWrite64 (
Value,
RegisterTableEntry->ValidBitStart,
RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
(UINTN) RegisterTableEntry->Value
);
AsmWriteCr3 (Value);
break;
case 4:
Value = AsmReadCr4 ();
Value = (UINTN) BitFieldWrite64 (
Value,
RegisterTableEntry->ValidBitStart,
RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
(UINTN) RegisterTableEntry->Value
);
AsmWriteCr4 (Value);
break;
default:
break;
}
break;
//
// The specified register is Model Specific Register
//
case Msr:
//
// If this function is called to restore register setting after INIT signal,
// there is no need to restore MSRs in register table.
//
if (RegisterTableEntry->ValidBitLength >= 64) {
//
// If length is not less than 64 bits, then directly write without reading
//
AsmWriteMsr64 (
RegisterTableEntry->Index,
RegisterTableEntry->Value
);
} else {
//
// Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode
// to make sure MSR read/write operation is atomic.
//
MsrSpinLock = GetMsrSpinLockByIndex (RegisterTableEntry->Index);
AcquireSpinLock (MsrSpinLock);
//
// Set the bit section according to bit start and length
//
AsmMsrBitFieldWrite64 (
RegisterTableEntry->Index,
RegisterTableEntry->ValidBitStart,
RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
RegisterTableEntry->Value
);
ReleaseSpinLock (MsrSpinLock);
}
break;
//
// Enable or disable cache
//
case CacheControl:
//
// If value of the entry is 0, then disable cache. Otherwise, enable cache.
//
if (RegisterTableEntry->Value == 0) {
AsmDisableCache ();
} else {
AsmEnableCache ();
}
break;
default:
break;
}
}
}
/**
AP initialization before SMBASE relocation in the S3 boot path.
**/
VOID
EarlyMPRendezvousProcedure (
VOID
)
{
CPU_REGISTER_TABLE *RegisterTableList;
UINT32 InitApicId;
UINTN Index;
LoadMtrrData (mAcpiCpuData.MtrrTable);
//
// Find processor number for this CPU.
//
RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable;
InitApicId = GetInitialApicId ();
for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
if (RegisterTableList[Index].InitialApicId == InitApicId) {
SetProcessorRegister (&RegisterTableList[Index]);
break;
}
}
//
// Count down the number with lock mechanism.
//
InterlockedDecrement (&mNumberToFinish);
}
/**
AP initialization after SMBASE relocation in the S3 boot path.
**/
VOID
MPRendezvousProcedure (
VOID
)
{
CPU_REGISTER_TABLE *RegisterTableList;
UINT32 InitApicId;
UINTN Index;
ProgramVirtualWireMode ();
DisableLvtInterrupts ();
RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
InitApicId = GetInitialApicId ();
for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
if (RegisterTableList[Index].InitialApicId == InitApicId) {
SetProcessorRegister (&RegisterTableList[Index]);
break;
}
}
//
// Count down the number with lock mechanism.
//
InterlockedDecrement (&mNumberToFinish);
}
/**
Prepares startup vector for APs.
This function prepares startup vector for APs.
@param WorkingBuffer The address of the work buffer.
**/
VOID
PrepareApStartupVector (
EFI_PHYSICAL_ADDRESS WorkingBuffer
)
{
EFI_PHYSICAL_ADDRESS StartupVector;
MP_ASSEMBLY_ADDRESS_MAP AddressMap;
//
// Get the address map of startup code for AP,
// including code size, and offset of long jump instructions to redirect.
//
ZeroMem (&AddressMap, sizeof (AddressMap));
AsmGetAddressMap (&AddressMap);
StartupVector = WorkingBuffer;
//
// Copy AP startup code to startup vector, and then redirect the long jump
// instructions for mode switching.
//
CopyMem ((VOID *) (UINTN) StartupVector, AddressMap.RendezvousFunnelAddress, AddressMap.Size);
*(UINT32 *) (UINTN) (StartupVector + AddressMap.FlatJumpOffset + 3) = (UINT32) (StartupVector + AddressMap.PModeEntryOffset);
if (AddressMap.LongJumpOffset != 0) {
*(UINT32 *) (UINTN) (StartupVector + AddressMap.LongJumpOffset + 2) = (UINT32) (StartupVector + AddressMap.LModeEntryOffset);
}
//
// Get the start address of exchange data between BSP and AP.
//
mExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (StartupVector + AddressMap.Size);
ZeroMem ((VOID *) mExchangeInfo, sizeof (MP_CPU_EXCHANGE_INFO));
CopyMem ((VOID *) (UINTN) &mExchangeInfo->GdtrProfile, (VOID *) (UINTN) mAcpiCpuData.GdtrProfile, sizeof (IA32_DESCRIPTOR));
CopyMem ((VOID *) (UINTN) &mExchangeInfo->IdtrProfile, (VOID *) (UINTN) mAcpiCpuData.IdtrProfile, sizeof (IA32_DESCRIPTOR));
//
// Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory
//
CopyMem ((VOID *) mExchangeInfo->GdtrProfile.Base, mGdtForAp, mExchangeInfo->GdtrProfile.Limit + 1);
CopyMem ((VOID *) mExchangeInfo->IdtrProfile.Base, mIdtForAp, mExchangeInfo->IdtrProfile.Limit + 1);
CopyMem ((VOID *)(UINTN) mAcpiCpuData.ApMachineCheckHandlerBase, mMachineCheckHandlerForAp, mAcpiCpuData.ApMachineCheckHandlerSize);
mExchangeInfo->StackStart = (VOID *) (UINTN) mAcpiCpuData.StackAddress;
mExchangeInfo->StackSize = mAcpiCpuData.StackSize;
mExchangeInfo->BufferStart = (UINT32) StartupVector;
mExchangeInfo->Cr3 = (UINT32) (AsmReadCr3 ());
}
/**
The function is invoked before SMBASE relocation in S3 path to restores CPU status.
The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
and restores MTRRs for both BSP and APs.
**/
VOID
EarlyInitializeCpu (
VOID
)
{
CPU_REGISTER_TABLE *RegisterTableList;
UINT32 InitApicId;
UINTN Index;
LoadMtrrData (mAcpiCpuData.MtrrTable);
//
// Find processor number for this CPU.
//
RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable;
InitApicId = GetInitialApicId ();
for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
if (RegisterTableList[Index].InitialApicId == InitApicId) {
SetProcessorRegister (&RegisterTableList[Index]);
break;
}
}
ProgramVirtualWireMode ();
PrepareApStartupVector (mAcpiCpuData.StartupVector);
mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
mExchangeInfo->ApFunction = (VOID *) (UINTN) EarlyMPRendezvousProcedure;
//
// Send INIT IPI - SIPI to all APs
//
SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
while (mNumberToFinish > 0) {
CpuPause ();
}
}
/**
The function is invoked after SMBASE relocation in S3 path to restores CPU status.
The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
data saved by normal boot path for both BSP and APs.
**/
VOID
InitializeCpu (
VOID
)
{
CPU_REGISTER_TABLE *RegisterTableList;
UINT32 InitApicId;
UINTN Index;
RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
InitApicId = GetInitialApicId ();
for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
if (RegisterTableList[Index].InitialApicId == InitApicId) {
SetProcessorRegister (&RegisterTableList[Index]);
break;
}
}
mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
//
// StackStart was updated when APs were waken up in EarlyInitializeCpu.
// Re-initialize StackAddress to original beginning address.
//
mExchangeInfo->StackStart = (VOID *) (UINTN) mAcpiCpuData.StackAddress;
mExchangeInfo->ApFunction = (VOID *) (UINTN) MPRendezvousProcedure;
//
// Send INIT IPI - SIPI to all APs
//
SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
while (mNumberToFinish > 0) {
CpuPause ();
}
}

View File

@ -0,0 +1,486 @@
/** @file
Implementation of SMM CPU Services Protocol.
Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
//
// SMM CPU Service Protocol instance
//
EFI_SMM_CPU_SERVICE_PROTOCOL mSmmCpuService = {
SmmGetProcessorInfo,
SmmSwitchBsp,
SmmAddProcessor,
SmmRemoveProcessor,
SmmWhoAmI,
SmmRegisterExceptionHandler
};
/**
Get Package ID/Core ID/Thread ID of a processor.
APIC ID must be an initial APIC ID.
The algorithm below assumes the target system has symmetry across physical package boundaries
with respect to the number of logical processors per package, number of cores per package.
@param ApicId APIC ID of the target logical processor.
@param Location Returns the processor location information.
**/
VOID
SmmGetProcessorLocation (
IN UINT32 ApicId,
OUT EFI_CPU_PHYSICAL_LOCATION *Location
)
{
UINTN ThreadBits;
UINTN CoreBits;
UINT32 RegEax;
UINT32 RegEbx;
UINT32 RegEcx;
UINT32 RegEdx;
UINT32 MaxCpuIdIndex;
UINT32 SubIndex;
UINTN LevelType;
UINT32 MaxLogicProcessorsPerPackage;
UINT32 MaxCoresPerPackage;
BOOLEAN TopologyLeafSupported;
ASSERT (Location != NULL);
ThreadBits = 0;
CoreBits = 0;
TopologyLeafSupported = FALSE;
//
// Check if the processor is capable of supporting more than one logical processor.
//
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
ASSERT ((RegEdx & BIT28) != 0);
//
// Assume three-level mapping of APIC ID: Package:Core:SMT.
//
//
// Get the max index of basic CPUID
//
AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
//
// If the extended topology enumeration leaf is available, it
// is the preferred mechanism for enumerating topology.
//
if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, &RegEax, &RegEbx, &RegEcx, NULL);
//
// If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
// basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
// supported on that processor.
//
if ((RegEbx & 0xffff) != 0) {
TopologyLeafSupported = TRUE;
//
// Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
// the SMT sub-field of x2APIC ID.
//
LevelType = (RegEcx >> 8) & 0xff;
ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
if ((RegEbx & 0xffff) > 1 ) {
ThreadBits = RegEax & 0x1f;
} else {
//
// HT is not supported
//
ThreadBits = 0;
}
//
// Software must not assume any "level type" encoding
// value to be related to any sub-leaf index, except sub-leaf 0.
//
SubIndex = 1;
do {
AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, SubIndex, &RegEax, NULL, &RegEcx, NULL);
LevelType = (RegEcx >> 8) & 0xff;
if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
CoreBits = (RegEax & 0x1f) - ThreadBits;
break;
}
SubIndex++;
} while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
}
}
if (!TopologyLeafSupported) {
AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
MaxLogicProcessorsPerPackage = (RegEbx >> 16) & 0xff;
if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &RegEax, NULL, NULL, NULL);
MaxCoresPerPackage = (RegEax >> 26) + 1;
} else {
//
// Must be a single-core processor.
//
MaxCoresPerPackage = 1;
}
ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1);
}
Location->Thread = ApicId & ~((-1) << ThreadBits);
Location->Core = (ApicId >> ThreadBits) & ~((-1) << CoreBits);
Location->Package = (ApicId >> (ThreadBits+ CoreBits));
}
/**
Gets processor information on the requested processor at the instant this call is made.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorNumber The handle number of processor.
@param[out] ProcessorInfoBuffer A pointer to the buffer where information for
the requested processor is deposited.
@retval EFI_SUCCESS Processor information was returned.
@retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
@retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
@retval EFI_NOT_FOUND The processor with the handle specified by
ProcessorNumber does not exist in the platform.
**/
EFI_STATUS
EFIAPI
SmmGetProcessorInfo (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINTN ProcessorNumber,
OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
)
{
//
// Check parameter
//
if (ProcessorNumber >= mMaxNumberOfCpus || ProcessorInfoBuffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {
return EFI_NOT_FOUND;
}
//
// Fill in processor information
//
CopyMem (ProcessorInfoBuffer, &gSmmCpuPrivate->ProcessorInfo[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION));
return EFI_SUCCESS;
}
/**
This service switches the requested AP to be the BSP since the next SMI.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
@retval EFI_SUCCESS BSP will be switched in next SMI.
@retval EFI_UNSUPPORTED Switching the BSP or a processor to be hot-removed is not supported.
@retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
@retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
**/
EFI_STATUS
EFIAPI
SmmSwitchBsp (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINTN ProcessorNumber
)
{
//
// Check parameter
//
if (ProcessorNumber >= mMaxNumberOfCpus) {
return EFI_INVALID_PARAMETER;
}
if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {
return EFI_NOT_FOUND;
}
if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone ||
gSmst->CurrentlyExecutingCpu == ProcessorNumber) {
return EFI_UNSUPPORTED;
}
//
// Setting of the BSP for next SMI is pending until all SMI handlers are finished
//
gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuSwitchBsp;
return EFI_SUCCESS;
}
/**
Notify that a processor was hot-added.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorId Local APIC ID of the hot-added processor.
@param[out] ProcessorNumber The handle number of the hot-added processor.
@retval EFI_SUCCESS The hot-addition of the specified processors was successfully notified.
@retval EFI_UNSUPPORTED Hot addition of processor is not supported.
@retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
@retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
@retval EFI_ALREADY_STARTED The processor is already online in the system.
**/
EFI_STATUS
EFIAPI
SmmAddProcessor (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINT64 ProcessorId,
OUT UINTN *ProcessorNumber
)
{
UINTN Index;
if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {
return EFI_UNSUPPORTED;
}
//
// Check parameter
//
if (ProcessorNumber == NULL || ProcessorId == INVALID_APIC_ID) {
return EFI_INVALID_PARAMETER;
}
//
// Check if the processor already exists
//
for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ProcessorId) {
return EFI_ALREADY_STARTED;
}
}
//
// Check CPU hot plug data. The CPU RAS handler should have created the mapping
// of the APIC ID to SMBASE.
//
for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
if (mCpuHotPlugData.ApicId[Index] == ProcessorId &&
gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == INVALID_APIC_ID) {
gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = ProcessorId;
gSmmCpuPrivate->ProcessorInfo[Index].StatusFlag = 0;
SmmGetProcessorLocation ((UINT32)ProcessorId, &gSmmCpuPrivate->ProcessorInfo[Index].Location);
*ProcessorNumber = Index;
gSmmCpuPrivate->Operation[Index] = SmmCpuAdd;
return EFI_SUCCESS;
}
}
return EFI_INVALID_PARAMETER;
}
/**
Notify that a processor was hot-removed.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorNumber The handle number of the hot-added processor.
@retval EFI_SUCCESS The hot-removal of the specified processors was successfully notified.
@retval EFI_UNSUPPORTED Hot removal of processor is not supported.
@retval EFI_UNSUPPORTED Hot removal of BSP is not supported.
@retval EFI_UNSUPPORTED Hot removal of a processor with pending hot-plug operation is not supported.
@retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
**/
EFI_STATUS
EFIAPI
SmmRemoveProcessor (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINTN ProcessorNumber
)
{
if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {
return EFI_UNSUPPORTED;
}
//
// Check parameter
//
if (ProcessorNumber >= mMaxNumberOfCpus ||
gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {
return EFI_INVALID_PARAMETER;
}
//
// Can't remove BSP
//
if (ProcessorNumber == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {
return EFI_UNSUPPORTED;
}
if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone) {
return EFI_UNSUPPORTED;
}
gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId = INVALID_APIC_ID;
mCpuHotPlugData.ApicId[ProcessorNumber] = INVALID_APIC_ID;
//
// Removal of the processor from the CPU list is pending until all SMI handlers are finished
//
gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuRemove;
return EFI_SUCCESS;
}
/**
This return the handle number for the calling processor.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[out] ProcessorNumber The handle number of currently executing processor.
@retval EFI_SUCCESS The current processor handle number was returned
in ProcessorNumber.
@retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
**/
EFI_STATUS
EFIAPI
SmmWhoAmI (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
OUT UINTN *ProcessorNumber
)
{
UINTN Index;
UINT64 ApicId;
//
// Check parameter
//
if (ProcessorNumber == NULL) {
return EFI_INVALID_PARAMETER;
}
ApicId = GetApicId ();
for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ApicId) {
*ProcessorNumber = Index;
return EFI_SUCCESS;
}
}
//
// This should not happen
//
ASSERT (FALSE);
return EFI_NOT_FOUND;
}
/**
Update the SMM CPU list per the pending operation.
This function is called after return from SMI handlers.
**/
VOID
SmmCpuUpdate (
VOID
)
{
UINTN Index;
//
// Handle pending BSP switch operations
//
for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
if (gSmmCpuPrivate->Operation[Index] == SmmCpuSwitchBsp) {
gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
mSmmMpSyncData->SwitchBsp = TRUE;
mSmmMpSyncData->CandidateBsp[Index] = TRUE;
}
}
//
// Handle pending hot-add operations
//
for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
if (gSmmCpuPrivate->Operation[Index] == SmmCpuAdd) {
gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
mNumberOfCpus++;
}
}
//
// Handle pending hot-remove operations
//
for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {
gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
mNumberOfCpus--;
}
}
}
/**
Register exception handler.
@param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.
@param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and
the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL
of the UEFI 2.0 specification.
@param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER
that is called when a processor interrupt occurs.
If this parameter is NULL, then the handler will be uninstalled.
@retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed.
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.
@retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
**/
EFI_STATUS
EFIAPI
SmmRegisterExceptionHandler (
IN EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
)
{
return RegisterCpuInterruptHandler (ExceptionType, InterruptHandler);
}
/**
Initialize SMM CPU Services.
It installs EFI SMM CPU Services Protocol.
@param ImageHandle The firmware allocated handle for the EFI image.
@retval EFI_SUCCESS EFI SMM CPU Services Protocol was installed successfully.
**/
EFI_STATUS
InitializeSmmCpuServices (
IN EFI_HANDLE Handle
)
{
EFI_STATUS Status;
Status = gSmst->SmmInstallProtocolInterface (
&Handle,
&gEfiSmmCpuServiceProtocolGuid,
EFI_NATIVE_INTERFACE,
&mSmmCpuService
);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@ -0,0 +1,181 @@
/** @file
Include file for SMM CPU Services protocol implementation.
Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _CPU_SERVICE_H_
#define _CPU_SERVICE_H_
typedef enum {
SmmCpuNone,
SmmCpuAdd,
SmmCpuRemove,
SmmCpuSwitchBsp
} SMM_CPU_OPERATION;
//
// SMM CPU Service Protocol function prototypes.
//
/**
Gets processor information on the requested processor at the instant this call is made.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorNumber The handle number of processor.
@param[out] ProcessorInfoBuffer A pointer to the buffer where information for
the requested processor is deposited.
@retval EFI_SUCCESS Processor information was returned.
@retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
@retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
@retval EFI_NOT_FOUND The processor with the handle specified by
ProcessorNumber does not exist in the platform.
**/
EFI_STATUS
EFIAPI
SmmGetProcessorInfo (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINTN ProcessorNumber,
OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
);
/**
This service switches the requested AP to be the BSP since the next SMI.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
@retval EFI_SUCCESS BSP will be switched in next SMI.
@retval EFI_UNSUPPORTED Switching the BSP or a processor to be hot-removed is not supported.
@retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
@retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
**/
EFI_STATUS
EFIAPI
SmmSwitchBsp (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINTN ProcessorNumber
);
/**
Notify that a processor was hot-added.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorId Local APIC ID of the hot-added processor.
@param[out] ProcessorNumber The handle number of the hot-added processor.
@retval EFI_SUCCESS The hot-addition of the specified processors was successfully notified.
@retval EFI_UNSUPPORTED Hot addition of processor is not supported.
@retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
@retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
@retval EFI_ALREADY_STARTED The processor is already online in the system.
**/
EFI_STATUS
EFIAPI
SmmAddProcessor (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINT64 ProcessorId,
OUT UINTN *ProcessorNumber
);
/**
Notify that a processor was hot-removed.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[in] ProcessorNumber The handle number of the hot-added processor.
@retval EFI_SUCCESS The hot-removal of the specified processors was successfully notified.
@retval EFI_UNSUPPORTED Hot removal of processor is not supported.
@retval EFI_UNSUPPORTED Hot removal of BSP is not supported.
@retval EFI_UNSUPPORTED Hot removal of a processor with pending hot-plug operation is not supported.
@retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
**/
EFI_STATUS
EFIAPI
SmmRemoveProcessor (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN UINTN ProcessorNumber
);
/**
This return the handle number for the calling processor.
@param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
@param[out] ProcessorNumber The handle number of currently executing processor.
@retval EFI_SUCCESS The current processor handle number was returned
in ProcessorNumber.
@retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
**/
EFI_STATUS
EFIAPI
SmmWhoAmI (
IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
OUT UINTN *ProcessorNumber
);
/**
Register exception handler.
@param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.
@param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and
the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL
of the UEFI 2.0 specification.
@param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER
that is called when a processor interrupt occurs.
If this parameter is NULL, then the handler will be uninstalled.
@retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed.
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.
@retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
**/
EFI_STATUS
EFIAPI
SmmRegisterExceptionHandler (
IN EFI_SMM_CPU_SERVICE_PROTOCOL *This,
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
);
//
// Internal function prototypes
//
/**
Update the SMM CPU list per the pending operation.
This function is called after return from SMI handlers.
**/
VOID
SmmCpuUpdate (
VOID
);
/**
Initialize SMM CPU Services.
It installs EFI SMM CPU Services Protocol.
@param ImageHandle The firmware allocated handle for the EFI image.
@retval EFI_SUCCESS EFI SMM CPU Services Protocol was installed successfully.
**/
EFI_STATUS
InitializeSmmCpuServices (
IN EFI_HANDLE Handle
);
#endif

View File

@ -0,0 +1,165 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# MpFuncs.S
#
# Abstract:
#
# This is the assembly code for Multi-processor S3 support
#
#------------------------------------------------------------------------------
.equ VacantFlag, 0x0
.equ NotVacantFlag, 0xff
.equ LockLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart
.equ StackStart, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x04
.equ StackSize, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x08
.equ RendezvousProc, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x0C
.equ GdtrProfile, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x10
.equ IdtrProfile, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x16
.equ BufferStart, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x1C
#-------------------------------------------------------------------------------------
#RendezvousFunnelProc procedure follows. All APs execute their procedure. This
#procedure serializes all the AP processors through an Init sequence. It must be
#noted that APs arrive here very raw...ie: real mode, no stack.
#ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
#IS IN MACHINE CODE.
#-------------------------------------------------------------------------------------
#RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
ASM_GLOBAL ASM_PFX(RendezvousFunnelProc)
ASM_PFX(RendezvousFunnelProc):
RendezvousFunnelProcStart:
# At this point CS = 0x(vv00) and ip= 0x0.
.byte 0x8c,0xc8 # mov ax, cs
.byte 0x8e,0xd8 # mov ds, ax
.byte 0x8e,0xc0 # mov es, ax
.byte 0x8e,0xd0 # mov ss, ax
.byte 0x33,0xc0 # xor ax, ax
.byte 0x8e,0xe0 # mov fs, ax
.byte 0x8e,0xe8 # mov gs, ax
flat32Start:
.byte 0xBE
.word BufferStart
.byte 0x66,0x8B,0x14 # mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer
.byte 0xBE
.word GdtrProfile
.byte 0x66 # db 66h
.byte 0x2E,0xF,0x1,0x14 # lgdt fword ptr cs:[si]
.byte 0xBE
.word IdtrProfile
.byte 0x66 # db 66h
.byte 0x2E,0xF,0x1,0x1C # lidt fword ptr cs:[si]
.byte 0x33,0xC0 # xor ax, ax
.byte 0x8E,0xD8 # mov ds, ax
.byte 0xF,0x20,0xC0 # mov eax, cr0 ; Get control register 0
.byte 0x66,0x83,0xC8,0x1 # or eax, 000000001h ; Set PE bit (bit #0)
.byte 0xF,0x22,0xC0 # mov cr0, eax
FLAT32_JUMP:
.byte 0x66,0x67,0xEA # far jump
.long 0x0 # 32-bit offset
.word 0x20 # 16-bit selector
PMODE_ENTRY: # protected mode entry point
movw $0x8,%ax
.byte 0x66
movw %ax,%ds
.byte 0x66
movw %ax,%es
.byte 0x66
movw %ax,%fs
.byte 0x66
movw %ax,%gs
.byte 0x66
movw %ax,%ss # Flat mode setup.
movl %edx,%esi
movl %esi,%edi
addl $LockLocation, %edi
movb $NotVacantFlag, %al
TestLock:
xchgb (%edi), %al
cmpb $NotVacantFlag, %al
jz TestLock
ProgramStack:
movl %esi,%edi
addl $StackSize, %edi
movl (%edi),%eax
movl %esi,%edi
addl $StackStart, %edi
addl (%edi),%eax
movl %eax,%esp
movl %eax,(%edi)
Releaselock:
movb $VacantFlag, %al
movl %esi,%edi
addl $LockLocation, %edi
xchgb (%edi), %al
#
# Call assembly function to initialize FPU.
#
lea ASM_PFX(InitializeFloatingPointUnits), %ebx
call *%ebx
#
# Call C Function
#
movl %esi,%edi
addl $RendezvousProc, %edi
movl (%edi),%eax
testl %eax,%eax
jz GoToSleep
call *%eax # Call C function
GoToSleep:
cli
hlt
jmp GoToSleep
RendezvousFunnelProcEnd:
#-------------------------------------------------------------------------------------
# AsmGetAddressMap (&AddressMap);
#-------------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(AsmGetAddressMap)
ASM_PFX(AsmGetAddressMap):
pushal
movl %esp,%ebp
movl 0x24(%ebp), %ebx
movl $RendezvousFunnelProcStart, (%ebx)
movl $(PMODE_ENTRY - RendezvousFunnelProcStart), 0x4(%ebx)
movl $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x8(%ebx)
movl $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0x0c(%ebx)
popal
ret

View File

@ -0,0 +1,168 @@
;------------------------------------------------------------------------------ ;
; Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
; MpFuncs.asm
;
; Abstract:
;
; This is the assembly code for Multi-processor S3 support
;
;-------------------------------------------------------------------------------
.686p
.model flat,C
.code
EXTERN InitializeFloatingPointUnits:PROC
VacantFlag Equ 00h
NotVacantFlag Equ 0ffh
LockLocation equ RendezvousFunnelProcEnd - RendezvousFunnelProcStart
StackStart equ LockLocation + 4h
StackSize equ LockLocation + 8h
RendezvousProc equ LockLocation + 0Ch
GdtrProfile equ LockLocation + 10h
IdtrProfile equ LockLocation + 16h
BufferStart equ LockLocation + 1Ch
;-------------------------------------------------------------------------------------
;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
;procedure serializes all the AP processors through an Init sequence. It must be
;noted that APs arrive here very raw...ie: real mode, no stack.
;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
;IS IN MACHINE CODE.
;-------------------------------------------------------------------------------------
;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
RendezvousFunnelProc PROC near C PUBLIC
RendezvousFunnelProcStart::
; At this point CS = 0x(vv00) and ip= 0x0.
db 8ch, 0c8h ; mov ax, cs
db 8eh, 0d8h ; mov ds, ax
db 8eh, 0c0h ; mov es, ax
db 8eh, 0d0h ; mov ss, ax
db 33h, 0c0h ; xor ax, ax
db 8eh, 0e0h ; mov fs, ax
db 8eh, 0e8h ; mov gs, ax
flat32Start::
db 0BEh
dw BufferStart ; mov si, BufferStart
db 66h, 8Bh, 14h ; mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer
db 0BEh
dw GdtrProfile ; mov si, GdtrProfile
db 66h ; db 66h
db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
db 0BEh
dw IdtrProfile ; mov si, IdtrProfile
db 66h ; db 66h
db 2Eh, 0Fh, 01h, 1Ch ; lidt fword ptr cs:[si]
db 33h, 0C0h ; xor ax, ax
db 8Eh, 0D8h ; mov ds, ax
db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Get control register 0
db 66h, 83h, 0C8h, 01h ; or eax, 000000001h ; Set PE bit (bit #0)
db 0Fh, 22h, 0C0h ; mov cr0, eax
FLAT32_JUMP::
db 66h, 67h, 0EAh ; far jump
dd 0h ; 32-bit offset
dw 20h ; 16-bit selector
PMODE_ENTRY:: ; protected mode entry point
mov ax, 8h
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax ; Flat mode setup.
mov esi, edx
mov edi, esi
add edi, LockLocation
mov al, NotVacantFlag
TestLock::
xchg byte ptr [edi], al
cmp al, NotVacantFlag
jz TestLock
ProgramStack::
mov edi, esi
add edi, StackSize
mov eax, dword ptr [edi]
mov edi, esi
add edi, StackStart
add eax, dword ptr [edi]
mov esp, eax
mov dword ptr [edi], eax
Releaselock::
mov al, VacantFlag
mov edi, esi
add edi, LockLocation
xchg byte ptr [edi], al
;
; Call assembly function to initialize FPU.
;
mov ebx, InitializeFloatingPointUnits
call ebx
;
; Call C Function
;
mov edi, esi
add edi, RendezvousProc
mov eax, dword ptr [edi]
test eax, eax
jz GoToSleep
call eax ; Call C function
GoToSleep::
cli
hlt
jmp $-2
RendezvousFunnelProc ENDP
RendezvousFunnelProcEnd::
;-------------------------------------------------------------------------------------
; AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
AsmGetAddressMap PROC near C PUBLIC
pushad
mov ebp,esp
mov ebx, dword ptr [ebp+24h]
mov dword ptr [ebx], RendezvousFunnelProcStart
mov dword ptr [ebx+4h], PMODE_ENTRY - RendezvousFunnelProcStart
mov dword ptr [ebx+8h], FLAT32_JUMP - RendezvousFunnelProcStart
mov dword ptr [ebx+0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
popad
ret
AsmGetAddressMap ENDP
END

View File

@ -0,0 +1,132 @@
/** @file
Page table manipulation functions for IA-32 processors
Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
SPIN_LOCK mPFLock;
/**
Create PageTable for SMM use.
@return PageTable Address
**/
UINT32
SmmInitPageTable (
VOID
)
{
UINTN PageFaultHandlerHookAddress;
IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
//
// Initialize spin lock
//
InitializeSpinLock (&mPFLock);
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
//
// Set own Page Fault entry instead of the default one, because SMM Profile
// feature depends on IRET instruction to do Single Step
//
PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile;
IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base;
IdtEntry += EXCEPT_IA32_PAGE_FAULT;
IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
IdtEntry->Bits.Reserved_0 = 0;
IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
} else {
//
// Register SMM Page Fault Handler
//
SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);
}
//
// Additional SMM IDT initialization for SMM stack guard
//
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
InitializeIDTSmmStackGuard ();
}
return Gen4GPageTable (0, TRUE);
}
/**
Page Fault handler for SMM use.
**/
VOID
SmiDefaultPFHandler (
VOID
)
{
CpuDeadLoop ();
}
/**
ThePage Fault handler wrapper for SMM use.
@param InterruptType Defines the type of interrupt or exception that
occurred on the processor.This parameter is processor architecture specific.
@param SystemContext A pointer to the processor context when
the interrupt occurred on the processor.
**/
VOID
EFIAPI
SmiPFHandler (
IN EFI_EXCEPTION_TYPE InterruptType,
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
UINTN PFAddress;
ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);
AcquireSpinLock (&mPFLock);
PFAddress = AsmReadCr2 ();
if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
(PFAddress >= mCpuHotPlugData.SmrrBase) &&
(PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {
DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));
CpuDeadLoop ();
}
//
// If a page fault occurs in SMM range
//
if ((PFAddress < mCpuHotPlugData.SmrrBase) ||
(PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {
if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));
DEBUG_CODE (
DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
);
CpuDeadLoop ();
}
}
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
SmmProfilePFHandler (
SystemContext.SystemContextIa32->Eip,
SystemContext.SystemContextIa32->ExceptionData
);
} else {
SmiDefaultPFHandler ();
}
ReleaseSpinLock (&mPFLock);
}

View File

@ -0,0 +1,48 @@
/** @file
Semaphore mechanism to indicate to the BSP that an AP has exited SMM
after SMBASE relocation.
Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
UINTN mSmmRelocationOriginalAddress;
volatile BOOLEAN *mRebasedFlag;
/**
Hook return address of SMM Save State so that semaphore code
can be executed immediately after AP exits SMM to indicate to
the BSP that an AP has exited SMM after SMBASE relocation.
@param[in] CpuIndex The processor index.
@param[in] RebasedFlag A pointer to a flag that is set to TRUE
immediately after AP exits SMM.
**/
VOID
SemaphoreHook (
IN UINTN CpuIndex,
IN volatile BOOLEAN *RebasedFlag
)
{
SMRAM_SAVE_STATE_MAP *CpuState;
mRebasedFlag = RebasedFlag;
CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
mSmmRelocationOriginalAddress = (UINTN)HookReturnFromSmm (
CpuIndex,
CpuState,
(UINT64)(UINTN)&SmmRelocationSemaphoreComplete,
(UINT64)(UINTN)&SmmRelocationSemaphoreComplete
);
}

View File

@ -0,0 +1,209 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# SmiEntry.S
#
# Abstract:
#
# Code template of the SMI handler for a particular processor
#
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(gcSmiHandlerTemplate)
ASM_GLOBAL ASM_PFX(gcSmiHandlerSize)
ASM_GLOBAL ASM_PFX(gcSmiHandlerOffset)
ASM_GLOBAL ASM_PFX(gSmiCr3)
ASM_GLOBAL ASM_PFX(gSmiStack)
ASM_GLOBAL ASM_PFX(gSmbase)
ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
ASM_GLOBAL ASM_PFX(gSmiHandlerIdtr)
.equ DSC_OFFSET, 0xfb00
.equ DSC_GDTPTR, 0x48
.equ DSC_GDTSIZ, 0x50
.equ DSC_CS, 0x14
.equ DSC_DS, 0x16
.equ DSC_SS, 0x18
.equ DSC_OTHERSEG, 0x1A
.equ PROTECT_MODE_CS, 0x08
.equ PROTECT_MODE_DS, 0x20
.equ TSS_SEGMENT, 0x40
.text
ASM_PFX(gcSmiHandlerOffset): .word _SmiHandler - _SmiEntryPoint + 0x8000
ASM_PFX(gcSmiHandlerTemplate):
_SmiEntryPoint:
.byte 0xbb # mov bx, imm16
.word _GdtDesc - _SmiEntryPoint + 0x8000
.byte 0x2e,0xa1 # mov ax, cs:[offset16]
.word DSC_OFFSET + DSC_GDTSIZ
decl %eax
movl %eax, %cs:(%edi) # mov cs:[bx], ax
.byte 0x66,0x2e,0xa1 # mov eax, cs:[offset16]
.word DSC_OFFSET + DSC_GDTPTR
movw %ax, %cs:2(%edi)
movw %ax, %bp # ebp = GDT base
.byte 0x66
lgdt %cs:(%edi)
# Patch ProtectedMode Segment
.byte 0xb8 # mov ax, imm16
.word PROTECT_MODE_CS # set AX for segment directly
movl %eax, %cs:-2(%edi) # mov cs:[bx - 2], ax
# Patch ProtectedMode entry
.byte 0x66, 0xbf # mov edi, SMBASE
ASM_PFX(gSmbase): .space 4
.byte 0x67
lea ((Start32bit - _SmiEntryPoint) + 0x8000)(%edi), %ax
movw %ax, %cs:-6(%edi)
movl %cr0, %ebx
.byte 0x66
andl $0x9ffafff3, %ebx
.byte 0x66
orl $0x23, %ebx
movl %ebx, %cr0
.byte 0x66,0xea
.space 4
.space 2
_GdtDesc: .space 4
.space 2
Start32bit:
movw $PROTECT_MODE_DS, %ax
movl %eax,%ds
movl %eax,%es
movl %eax,%fs
movl %eax,%gs
movl %eax,%ss
.byte 0xbc # mov esp, imm32
ASM_PFX(gSmiStack): .space 4
movl $ASM_PFX(gSmiHandlerIdtr), %eax
lidt (%eax)
jmp ProtFlatMode
ProtFlatMode:
.byte 0xb8 # mov eax, imm32
ASM_PFX(gSmiCr3): .space 4
movl %eax, %cr3
#
# Need to test for CR4 specific bit support
#
movl $1, %eax
cpuid # use CPUID to determine if specific CR4 bits are supported
xorl %eax, %eax # Clear EAX
testl $BIT2, %edx # Check for DE capabilities
jz L8
orl $BIT3, %eax
L8:
testl $BIT6, %edx # Check for PAE capabilities
jz L9
orl $BIT5, %eax
L9:
testl $BIT7, %edx # Check for MCE capabilities
jz L10
orl $BIT6, %eax
L10:
testl $BIT24, %edx # Check for FXSR capabilities
jz L11
orl $BIT9, %eax
L11:
testl $BIT25, %edx # Check for SSE capabilities
jz L12
orl $BIT10, %eax
L12: # as cr4.PGE is not set here, refresh cr3
movl %eax, %cr4 # in PreModifyMtrrs() to flush TLB.
movl %cr0, %ebx
orl $0x080010000, %ebx # enable paging + WP
movl %ebx, %cr0
leal DSC_OFFSET(%edi),%ebx
movw DSC_DS(%ebx),%ax
movl %eax, %ds
movw DSC_OTHERSEG(%ebx),%ax
movl %eax, %es
movl %eax, %fs
movl %eax, %gs
movw DSC_SS(%ebx),%ax
movl %eax, %ss
cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
jz L5
# Load TSS
movb $0x89, (TSS_SEGMENT + 5)(%ebp) # clear busy flag
movl $TSS_SEGMENT, %eax
ltrw %ax
L5:
# jmp _SmiHandler # instruction is not needed
_SmiHandler:
# below step is needed, because STM does not run above code.
# we have to run below code to set IDT/CR0/CR4
movl $ASM_PFX(gSmiHandlerIdtr), %eax
lidt (%eax)
movl %cr0, %eax
orl $0x00000022, %eax
orl $0x00010000, %eax # enable WP
movl %eax, %cr0
#
# Need to test for CR4 specific bit support
#
movl $1, %eax
cpuid # use CPUID to determine if specific CR4 bits are supported
movl %cr4, %eax # init EAX
testl $BIT2, %edx # Check for DE capabilities
jz L28
orl $BIT3, %eax
L28:
testl $BIT6, %edx # Check for PAE capabilities
jz L29
orl $BIT5, %eax
L29:
testl $BIT7, %edx # Check for MCE capabilities
jz L30
orl $BIT6, %eax
L30:
testl $BIT24, %edx # Check for FXSR capabilities
jz L31
orl $BIT9, %eax
L31:
testl $BIT25, %edx # Check for SSE capabilities
jz L32
orl $BIT10, %eax
L32: # as cr4.PGE is not set here, refresh cr3
movl %eax, %cr4 # in PreModifyMtrrs() to flush TLB.
# STM init finish
movl (%esp), %ebx
pushl %ebx
movl $ASM_PFX(CpuSmmDebugEntry), %eax
call *%eax
popl %ecx
pushl %ebx
movl $ASM_PFX(SmiRendezvous), %eax
call *%eax
popl %ecx
pushl %ebx
movl $ASM_PFX(CpuSmmDebugExit), %eax
call *%eax
popl %ecx
rsm
ASM_PFX(gcSmiHandlerSize): .word . - _SmiEntryPoint

View File

@ -0,0 +1,219 @@
;------------------------------------------------------------------------------ ;
; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
; SmiEntry.asm
;
; Abstract:
;
; Code template of the SMI handler for a particular processor
;
;-------------------------------------------------------------------------------
.686p
.model flat,C
.xmm
DSC_OFFSET EQU 0fb00h
DSC_GDTPTR EQU 48h
DSC_GDTSIZ EQU 50h
DSC_CS EQU 14h
DSC_DS EQU 16h
DSC_SS EQU 18h
DSC_OTHERSEG EQU 1Ah
PROTECT_MODE_CS EQU 08h
PROTECT_MODE_DS EQU 20h
TSS_SEGMENT EQU 40h
SmiRendezvous PROTO C
CpuSmmDebugEntry PROTO C
CpuSmmDebugExit PROTO C
EXTERNDEF gcSmiHandlerTemplate:BYTE
EXTERNDEF gcSmiHandlerSize:WORD
EXTERNDEF gcSmiHandlerOffset:WORD
EXTERNDEF gSmiCr3:DWORD
EXTERNDEF gSmiStack:DWORD
EXTERNDEF gSmbase:DWORD
EXTERNDEF FeaturePcdGet (PcdCpuSmmStackGuard):BYTE
EXTERNDEF gSmiHandlerIdtr:FWORD
.const
gcSmiHandlerOffset DW _SmiHandler - _SmiEntryPoint + 8000h
.code
gcSmiHandlerTemplate LABEL BYTE
_SmiEntryPoint:
DB 0bbh ; mov bx, imm16
DW offset _GdtDesc - _SmiEntryPoint + 8000h
DB 2eh, 0a1h ; mov ax, cs:[offset16]
DW DSC_OFFSET + DSC_GDTSIZ
dec eax
mov cs:[edi], eax ; mov cs:[bx], ax
DB 66h, 2eh, 0a1h ; mov eax, cs:[offset16]
DW DSC_OFFSET + DSC_GDTPTR
mov cs:[edi + 2], ax ; mov cs:[bx + 2], eax
mov bp, ax ; ebp = GDT base
DB 66h
lgdt fword ptr cs:[edi] ; lgdt fword ptr cs:[bx]
; Patch ProtectedMode Segment
DB 0b8h ; mov ax, imm16
DW PROTECT_MODE_CS ; set AX for segment directly
mov cs:[edi - 2], eax ; mov cs:[bx - 2], ax
; Patch ProtectedMode entry
DB 66h, 0bfh ; mov edi, SMBASE
gSmbase DD ?
DB 67h
lea ax, [edi + (@32bit - _SmiEntryPoint) + 8000h]
mov cs:[edi - 6], ax ; mov cs:[bx - 6], eax
mov ebx, cr0
DB 66h
and ebx, 9ffafff3h
DB 66h
or ebx, 23h
mov cr0, ebx
DB 66h, 0eah
DD ?
DW ?
_GdtDesc FWORD ?
@32bit:
mov ax, PROTECT_MODE_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
DB 0bch ; mov esp, imm32
gSmiStack DD ?
mov eax, offset gSmiHandlerIdtr
lidt fword ptr [eax]
jmp ProtFlatMode
ProtFlatMode:
DB 0b8h ; mov eax, imm32
gSmiCr3 DD ?
mov cr3, eax
;
; Need to test for CR4 specific bit support
;
mov eax, 1
cpuid ; use CPUID to determine if specific CR4 bits are supported
xor eax, eax ; Clear EAX
test edx, BIT2 ; Check for DE capabilities
jz @f
or eax, BIT3
@@:
test edx, BIT6 ; Check for PAE capabilities
jz @f
or eax, BIT5
@@:
test edx, BIT7 ; Check for MCE capabilities
jz @f
or eax, BIT6
@@:
test edx, BIT24 ; Check for FXSR capabilities
jz @f
or eax, BIT9
@@:
test edx, BIT25 ; Check for SSE capabilities
jz @f
or eax, BIT10
@@: ; as cr4.PGE is not set here, refresh cr3
mov cr4, eax ; in PreModifyMtrrs() to flush TLB.
mov ebx, cr0
or ebx, 080010000h ; enable paging + WP
mov cr0, ebx
lea ebx, [edi + DSC_OFFSET]
mov ax, [ebx + DSC_DS]
mov ds, eax
mov ax, [ebx + DSC_OTHERSEG]
mov es, eax
mov fs, eax
mov gs, eax
mov ax, [ebx + DSC_SS]
mov ss, eax
cmp FeaturePcdGet (PcdCpuSmmStackGuard), 0
jz @F
; Load TSS
mov byte ptr [ebp + TSS_SEGMENT + 5], 89h ; clear busy flag
mov eax, TSS_SEGMENT
ltr ax
@@:
; jmp _SmiHandler ; instruction is not needed
_SmiHandler PROC
; below step is needed, because STM does not run above code.
; we have to run below code to set IDT/CR0/CR4
mov eax, offset gSmiHandlerIdtr
lidt fword ptr [eax]
mov eax, cr0
or eax, 00000022h
or eax, 00010000h ; enable WP
mov cr0, eax
;
; Need to test for CR4 specific bit support
;
mov eax, 1
cpuid ; use CPUID to determine if specific CR4 bits are supported
mov eax, cr4 ; init EAX
test edx, BIT2 ; Check for DE capabilities
jz @f
or eax, BIT3
@@:
test edx, BIT6 ; Check for PAE capabilities
jz @f
or eax, BIT5
@@:
test edx, BIT7 ; Check for MCE capabilities
jz @f
or eax, BIT6
@@:
test edx, BIT24 ; Check for FXSR capabilities
jz @f
or eax, BIT9
@@:
test edx, BIT25 ; Check for SSE capabilities
jz @f
or eax, BIT10
@@: ; as cr4.PGE is not set here, refresh cr3
mov cr4, eax ; in PreModifyMtrrs() to flush TLB.
; STM init finish
mov ebx, [esp] ; CPU Index
push ebx
mov eax, CpuSmmDebugEntry
call eax
pop ecx
push ebx
mov eax, SmiRendezvous
call eax
pop ecx
push ebx
mov eax, CpuSmmDebugExit
call eax
pop ecx
rsm
_SmiHandler ENDP
gcSmiHandlerSize DW $ - _SmiEntryPoint
END

View File

@ -0,0 +1,956 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# SmiException.S
#
# Abstract:
#
# Exception handlers used in SM mode
#
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(SmiPFHandler)
ASM_GLOBAL ASM_PFX(PageFaultStubFunction)
ASM_GLOBAL ASM_PFX(gSmiMtrrs)
ASM_GLOBAL ASM_PFX(gcSmiIdtr)
ASM_GLOBAL ASM_PFX(gcSmiGdtr)
ASM_GLOBAL ASM_PFX(gcPsd)
ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
ASM_GLOBAL ASM_PFX(SmmStmExceptionHandler)
ASM_GLOBAL ASM_PFX(SmmStmSetup)
ASM_GLOBAL ASM_PFX(SmmStmTeardown)
.data
NullSeg: .quad 0 # reserved by architecture
CodeSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x9b
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
ProtModeCodeSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x9b
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
ProtModeSsSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x93
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
DataSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x93
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
CodeSeg16:
.word -1
.word 0
.byte 0
.byte 0x9b
.byte 0x8f
.byte 0
DataSeg16:
.word -1
.word 0
.byte 0
.byte 0x93
.byte 0x8f
.byte 0
CodeSeg64:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x9b
.byte 0xaf # LimitHigh
.byte 0 # BaseHigh
.equ GDT_SIZE, .- NullSeg
TssSeg:
.word TSS_DESC_SIZE -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x89
.byte 0x00 # LimitHigh
.byte 0 # BaseHigh
ExceptionTssSeg:
.word TSS_DESC_SIZE - 1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x89
.byte 0x00 # LimitHigh
.byte 0 # BaseHigh
.equ CODE_SEL, CodeSeg32 - NullSeg
.equ DATA_SEL, DataSeg32 - NullSeg
.equ TSS_SEL, TssSeg - NullSeg
.equ EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
# IA32 TSS fields
.equ TSS_ESP0, 4
.equ TSS_SS0, 8
.equ TSS_ESP1, 12
.equ TSS_SS1, 16
.equ TSS_ESP2, 20
.equ TSS_SS2, 24
.equ TSS_CR3, 28
.equ TSS_EIP, 32
.equ TSS_EFLAGS, 36
.equ TSS_EAX, 40
.equ TSS_ECX, 44
.equ TSS_EDX, 48
.equ TSS_EBX, 52
.equ TSS_ESP, 56
.equ TSS_EBP, 60
.equ TSS_ESI, 64
.equ TSS_EDI, 68
.equ TSS_ES, 72
.equ TSS_CS, 76
.equ TSS_SS, 80
.equ TSS_DS, 84
.equ TSS_FS, 88
.equ TSS_GS, 92
.equ TSS_LDT, 96
# Create 2 TSS segments just after GDT
TssDescriptor:
.word 0 # PreviousTaskLink
.word 0 # Reserved
.long 0 # ESP0
.word 0 # SS0
.word 0 # Reserved
.long 0 # ESP1
.word 0 # SS1
.word 0 # Reserved
.long 0 # ESP2
.word 0 # SS2
.word 0 # Reserved
.long 0 # CR3
.long 0 # EIP
.long 0 # EFLAGS
.long 0 # EAX
.long 0 # ECX
.long 0 # EDX
.long 0 # EBX
.long 0 # ESP
.long 0 # EBP
.long 0 # ESI
.long 0 # EDI
.word 0 # ES
.word 0 # Reserved
.word 0 # CS
.word 0 # Reserved
.word 0 # SS
.word 0 # Reserved
.word 0 # DS
.word 0 # Reserved
.word 0 # FS
.word 0 # Reserved
.word 0 # GS
.word 0 # Reserved
.word 0 # LDT Selector
.word 0 # Reserved
.word 0 # T
.word 0 # I/O Map Base
.equ TSS_DESC_SIZE, . - TssDescriptor
ExceptionTssDescriptor:
.word 0 # PreviousTaskLink
.word 0 # Reserved
.long 0 # ESP0
.word 0 # SS0
.word 0 # Reserved
.long 0 # ESP1
.word 0 # SS1
.word 0 # Reserved
.long 0 # ESP2
.word 0 # SS2
.word 0 # Reserved
.long 0 # CR3
.long PFHandlerEntry # EIP
.long 00000002 # EFLAGS
.long 0 # EAX
.long 0 # ECX
.long 0 # EDX
.long 0 # EBX
.long 0 # ESP
.long 0 # EBP
.long 0 # ESI
.long 0 # EDI
.word DATA_SEL # ES
.word 0 # Reserved
.word CODE_SEL # CS
.word 0 # Reserved
.word DATA_SEL # SS
.word 0 # Reserved
.word DATA_SEL # DS
.word 0 # Reserved
.word DATA_SEL # FS
.word 0 # Reserved
.word DATA_SEL # GS
.word 0 # Reserved
.word 0 # LDT Selector
.word 0 # Reserved
.word 0 # T
.word 0 # I/O Map Base
ASM_PFX(gcPsd):
.ascii "TXTPSSIG"
.word PSD_SIZE
.word 1 # Version
.long 0 # LocalApicId
.byte 0x5 # Cr4Pse;Cr4Pae;Intel64Mode;ExecutionDisableOutsideSmrr
.byte 0 # BIOS to STM
.byte 0 # STM to BIOS
.byte 0
.word CODE_SEL
.word DATA_SEL
.word DATA_SEL
.word DATA_SEL
.word 0
.word 0
.quad 0 # SmmCr3
.long ASM_PFX(_OnStmSetup)
.long 0
.long ASM_PFX(_OnStmTeardown)
.long 0
.quad 0 # SmmSmiHandlerRip - SMM guest entrypoint
.quad 0 # SmmSmiHandlerRsp
.long NullSeg
.long 0
.long GDT_SIZE
.long 0x80010100 # RequiredStmSmmRevId
.long ASM_PFX(_OnException)
.long 0
.quad 0 # ExceptionStack
.quad DATA_SEL
.quad 0x1F # ExceptionFilter
.long 0
.long ASM_PFX(gSmiMtrrs)
.long 0
.quad 0 # BiosHwResourceRequirementsPtr
.quad 0 # AcpiRsdp
.byte 0 # PhysicalAddressBits
.equ PSD_SIZE, . - ASM_PFX(gcPsd)
ASM_PFX(gcSmiGdtr): .word GDT_SIZE - 1
.long NullSeg
ASM_PFX(gcSmiIdtr): .word IDT_SIZE - 1
.long _SmiIDT
_SmiIDT:
# The following segment repeats 32 times:
# No. 1
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 2
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 3
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 4
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 5
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 6
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 7
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 8
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 9
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 10
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 11
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 12
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 13
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 14
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 15
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 16
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 17
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 18
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 19
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 20
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 21
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 22
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 23
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 24
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 25
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 26
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 27
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 28
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 29
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 30
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 31
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
# No. 32
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.equ IDT_SIZE, . - _SmiIDT
TaskGateDescriptor:
.word 0 # Reserved
.word EXCEPTION_TSS_SEL # TSS Segment selector
.byte 0 # Reserved
.byte 0x85 # Task Gate, present, DPL = 0
.word 0 # Reserved
.text
#------------------------------------------------------------------------------
# PageFaultIdtHandlerSmmProfile is the entry point for all exceptions
#
# Stack:
#+---------------------+
#+ EFlags +
#+---------------------+
#+ CS +
#+---------------------+
#+ EIP +
#+---------------------+
#+ Error Code +
#+---------------------+
#+ Vector Number +
#+---------------------+
#+ EBP +
#+---------------------+ <-- EBP
#
# RSP set to odd multiple of 8 means ErrCode PRESENT
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile)
ASM_PFX(PageFaultIdtHandlerSmmProfile):
pushl $0x0e # Page Fault
pushl %ebp
movl %esp, %ebp
#
# Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
# is 16-byte aligned
#
andl $0xfffffff0, %esp
subl $12, %esp
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
pushl %eax
pushl %ecx
pushl %edx
pushl %ebx
leal (6*4)(%ebp), %ecx
pushl %ecx # ESP
pushl (%ebp) # EBP
pushl %esi
pushl %edi
## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
movl %ss, %eax
pushl %eax
movzwl (4*4)(%ebp), %eax
pushl %eax
movl %ds, %eax
pushl %eax
movl %es, %eax
pushl %eax
movl %fs, %eax
pushl %eax
movl %gs, %eax
pushl %eax
## UINT32 Eip;
movl (3*4)(%ebp), %eax
pushl %eax
## UINT32 Gdtr[2], Idtr[2];
subl $8, %esp
sidt (%esp)
movl 2(%esp), %eax
xchgl (%esp), %eax
andl $0xffff, %eax
movl %eax, 4(%esp)
subl $8, %esp
sgdt (%esp)
movl 2(%esp), %eax
xchgl (%esp), %eax
andl $0xffff, %eax
movl %eax, 4(%esp)
## UINT32 Ldtr, Tr;
xorl %eax, %eax
strw %ax
pushl %eax
sldtw %ax
pushl %eax
## UINT32 EFlags;
movl (5*4)(%ebp), %eax
pushl %eax
## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
movl %cr4, %eax
orl $0x208, %eax
movl %eax, %cr4
pushl %eax
movl %cr3, %eax
pushl %eax
movl %cr2, %eax
pushl %eax
xorl %eax, %eax
pushl %eax
movl %cr0, %eax
pushl %eax
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
movl %dr7, %eax
pushl %eax
movl %dr6, %eax
pushl %eax
movl %dr3, %eax
pushl %eax
movl %dr2, %eax
pushl %eax
movl %dr1, %eax
pushl %eax
movl %dr0, %eax
pushl %eax
## FX_SAVE_STATE_IA32 FxSaveState;
subl $512, %esp
movl %esp, %edi
.byte 0x0f, 0xae, 0x07 #fxsave [edi]
# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
cld
## UINT32 ExceptionData;
pushl (2*4)(%ebp)
## call into exception handler
## Prepare parameter and call
movl %esp, %edx
pushl %edx
movl (1*4)(%ebp), %edx
pushl %edx
#
# Call External Exception Handler
#
movl $ASM_PFX(SmiPFHandler), %eax
call *%eax
addl $8, %esp
jmp L4
L4:
## UINT32 ExceptionData;
addl $4, %esp
## FX_SAVE_STATE_IA32 FxSaveState;
movl %esp, %esi
.byte 0xf, 0xae, 0xe # fxrstor [esi]
addl $512, %esp
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
## Skip restoration of DRx registers to support debuggers
## that set breakpoints in interrupt/exception context
addl $4*6, %esp
## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
popl %eax
movl %eax, %cr0
addl $4, %esp # not for Cr1
popl %eax
movl %eax, %cr2
popl %eax
movl %eax, %cr3
popl %eax
movl %eax, %cr4
## UINT32 EFlags;
popl (5*4)(%ebp)
## UINT32 Ldtr, Tr;
## UINT32 Gdtr[2], Idtr[2];
## Best not let anyone mess with these particular registers...
addl $24, %esp
## UINT32 Eip;
popl (3*4)(%ebp)
## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
## NOTE - modified segment registers could hang the debugger... We
## could attempt to insulate ourselves against this possibility,
## but that poses risks as well.
##
popl %gs
popl %fs
popl %es
popl %ds
popl (4*4)(%ebp)
popl %ss
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
popl %edi
popl %esi
addl $4, %esp # not for ebp
addl $4, %esp # not for esp
popl %ebx
popl %edx
popl %ecx
popl %eax
movl %ebp, %esp
popl %ebp
# Enable TF bit after page fault handler runs
btsl $8, 16(%esp) # EFLAGS
addl $8, %esp # skip INT# & ErrCode
Return:
iret
#
# Page Fault Exception Handler entry when SMM Stack Guard is enabled
# Executiot starts here after a task switch
#
PFHandlerEntry:
#
# Get this processor's TSS
#
subl $8, %esp
sgdt 2(%esp)
movl 4(%esp), %eax # GDT base
addl $8, %esp
movl (TSS_SEL+2)(%eax), %ecx
shll $8, %ecx
movb (TSS_SEL+7)(%eax), %cl
rorl $8, %ecx # ecx = TSS base
movl %esp, %ebp
#
# Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
# is 16-byte aligned
#
andl $0xfffffff0, %esp
subl $12, %esp
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
pushl TSS_EAX(%ecx)
pushl TSS_ECX(%ecx)
pushl TSS_EDX(%ecx)
pushl TSS_EBX(%ecx)
pushl TSS_ESP(%ecx)
pushl TSS_EBP(%ecx)
pushl TSS_ESI(%ecx)
pushl TSS_EDI(%ecx)
## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
movzwl TSS_SS(%ecx), %eax
pushl %eax
movzwl TSS_CS(%ecx), %eax
pushl %eax
movzwl TSS_DS(%ecx), %eax
pushl %eax
movzwl TSS_ES(%ecx), %eax
pushl %eax
movzwl TSS_FS(%ecx), %eax
pushl %eax
movzwl TSS_GS(%ecx), %eax
pushl %eax
## UINT32 Eip;
pushl TSS_EIP(%ecx)
## UINT32 Gdtr[2], Idtr[2];
subl $8, %esp
sidt (%esp)
movl 2(%esp), %eax
xchgl (%esp), %eax
andl $0xFFFF, %eax
movl %eax, 4(%esp)
subl $8, %esp
sgdt (%esp)
movl 2(%esp), %eax
xchgl (%esp), %eax
andl $0xFFFF, %eax
movl %eax, 4(%esp)
## UINT32 Ldtr, Tr;
movl $TSS_SEL, %eax
pushl %eax
movzwl TSS_LDT(%ecx), %eax
pushl %eax
## UINT32 EFlags;
pushl TSS_EFLAGS(%ecx)
## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
movl %cr4, %eax
orl $0x208, %eax
movl %eax, %cr4
pushl %eax
movl %cr3, %eax
pushl %eax
movl %cr2, %eax
pushl %eax
xorl %eax, %eax
pushl %eax
movl %cr0, %eax
pushl %eax
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
movl %dr7, %eax
pushl %eax
movl %dr6, %eax
pushl %eax
movl %dr3, %eax
pushl %eax
movl %dr2, %eax
pushl %eax
movl %dr1, %eax
pushl %eax
movl %dr0, %eax
pushl %eax
## FX_SAVE_STATE_IA32 FxSaveState;
## Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
## when executing fxsave/fxrstor instruction
clts
subl $512, %esp
movl %esp, %edi
.byte 0x0f, 0xae, 0x07 #fxsave [edi]
# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
cld
## UINT32 ExceptionData;
pushl (%ebp)
## call into exception handler
movl %ecx, %ebx
movl $ASM_PFX(SmiPFHandler), %eax
## Prepare parameter and call
movl %esp, %edx
pushl %edx
movl $14, %edx
pushl %edx
#
# Call External Exception Handler
#
call *%eax
addl $8, %esp
movl %ebx, %ecx
## UINT32 ExceptionData;
addl $4, %esp
## FX_SAVE_STATE_IA32 FxSaveState;
movl %esp, %esi
.byte 0xf, 0xae, 0xe # fxrstor [esi]
addl $512, %esp
## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
## Skip restoration of DRx registers to support debuggers
## that set breakpoints in interrupt/exception context
addl $4*6, %esp
## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
popl %eax
movl %eax, %cr0
addl $4, %esp # not for Cr1
popl %eax
movl %eax, %cr2
popl %eax
movl %eax, TSS_CR3(%ecx)
popl %eax
movl %eax, %cr4
## UINT32 EFlags;
popl TSS_EFLAGS(%ecx)
## UINT32 Ldtr, Tr;
## UINT32 Gdtr[2], Idtr[2];
## Best not let anyone mess with these particular registers...
addl $24, %esp
## UINT32 Eip;
popl TSS_EIP(%ecx)
## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
## NOTE - modified segment registers could hang the debugger... We
## could attempt to insulate ourselves against this possibility,
## but that poses risks as well.
##
popl %eax
movw %ax, TSS_GS(%ecx)
popl %eax
movw %ax, TSS_FS(%ecx)
popl %eax
movw %ax, TSS_ES(%ecx)
popl %eax
movw %ax, TSS_DS(%ecx)
popl %eax
movw %ax, TSS_CS(%ecx)
popl %eax
movw %ax, TSS_SS(%ecx)
## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
popl TSS_EDI(%ecx)
popl TSS_ESI(%ecx)
addl $4, %esp # not for ebp
addl $4, %esp # not for esp
popl TSS_EBX(%ecx)
popl TSS_EDX(%ecx)
popl TSS_ECX(%ecx)
popl TSS_EAX(%ecx)
movl %ebp, %esp
# Set single step DB# if SMM profile is enabled and page fault exception happens
cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
jz Done2
# Create return context for iret in stub function
movl TSS_ESP(%ecx), %eax # Get old stack pointer
movl TSS_EIP(%ecx), %ebx
movl %ebx, -0xc(%eax) # create EIP in old stack
movzwl TSS_CS(%ecx), %ebx
movl %ebx, -0x8(%eax) # create CS in old stack
movl TSS_EFLAGS(%ecx), %ebx
btsl $8,%ebx
movl %ebx, -0x4(%eax) # create eflags in old stack
movl TSS_ESP(%ecx), %eax # Get old stack pointer
subl $12, %eax # minus 12 byte
movl %eax, TSS_ESP(%ecx) # Set new stack pointer
# Replace the EIP of interrupted task with stub function
movl $ASM_PFX(PageFaultStubFunction), %eax
movl %eax, TSS_EIP(%ecx)
# Jump to the iret so next page fault handler as a task will start again after iret.
Done2:
addl $4, %esp # skip ErrCode
jmp Return
ASM_PFX(PageFaultStubFunction):
#
# we need clean TS bit in CR0 to execute
# x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
#
clts
iret
ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard)
ASM_PFX(InitializeIDTSmmStackGuard):
pushl %ebx
#
# If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
# is a Task Gate Descriptor so that when a Page Fault Exception occurs,
# the processors can use a known good stack in case stack ran out.
#
leal _SmiIDT + 14 * 8, %ebx
leal TaskGateDescriptor, %edx
movl (%edx), %eax
movl %eax, (%ebx)
movl 4(%edx), %eax
movl %eax, 4(%ebx)
popl %ebx
ret
#------------------------------------------------------------------------------
# SMM Exception handlers
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(_OnException)
ASM_PFX(_OnException):
movl %esp, %ecx
pushl %ecx
call ASM_PFX(SmmStmExceptionHandler)
addl $4, %esp
movl %eax, %ebx
movl $4, %eax
.byte 0xf, 0x1, 0xc1 # VMCALL
jmp .
ASM_GLOBAL ASM_PFX(_OnStmSetup)
ASM_PFX(_OnStmSetup):
call ASM_PFX(SmmStmSetup)
rsm
ASM_GLOBAL ASM_PFX(_OnStmTeardown)
ASM_PFX(_OnStmTeardown):
call ASM_PFX(SmmStmTeardown)
rsm

View File

@ -0,0 +1,780 @@
;------------------------------------------------------------------------------ ;
; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
; SmiException.asm
;
; Abstract:
;
; Exception handlers used in SM mode
;
;-------------------------------------------------------------------------------
.686p
.model flat,C
EXTERNDEF SmiPFHandler:PROC
EXTERNDEF PageFaultStubFunction:PROC
EXTERNDEF gSmiMtrrs:QWORD
EXTERNDEF gcSmiIdtr:FWORD
EXTERNDEF gcSmiGdtr:FWORD
EXTERNDEF gcPsd:BYTE
EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE
SmmStmExceptionHandler PROTO
SmmStmSetup PROTO
SmmStmTeardown PROTO
.data
NullSeg DQ 0 ; reserved by architecture
CodeSeg32 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 9bh
DB 0cfh ; LimitHigh
DB 0 ; BaseHigh
ProtModeCodeSeg32 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 9bh
DB 0cfh ; LimitHigh
DB 0 ; BaseHigh
ProtModeSsSeg32 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 93h
DB 0cfh ; LimitHigh
DB 0 ; BaseHigh
DataSeg32 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 93h
DB 0cfh ; LimitHigh
DB 0 ; BaseHigh
CodeSeg16 LABEL QWORD
DW -1
DW 0
DB 0
DB 9bh
DB 8fh
DB 0
DataSeg16 LABEL QWORD
DW -1
DW 0
DB 0
DB 93h
DB 8fh
DB 0
CodeSeg64 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 9bh
DB 0afh ; LimitHigh
DB 0 ; BaseHigh
GDT_SIZE = $ - offset NullSeg
TssSeg LABEL QWORD
DW TSS_DESC_SIZE - 1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 89h
DB 00h ; LimitHigh
DB 0 ; BaseHigh
ExceptionTssSeg LABEL QWORD
DW TSS_DESC_SIZE - 1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 89h
DB 00h ; LimitHigh
DB 0 ; BaseHigh
CODE_SEL = offset CodeSeg32 - offset NullSeg
DATA_SEL = offset DataSeg32 - offset NullSeg
TSS_SEL = offset TssSeg - offset NullSeg
EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg
IA32_TSS STRUC
DW ?
DW ?
ESP0 DD ?
SS0 DW ?
DW ?
ESP1 DD ?
SS1 DW ?
DW ?
ESP2 DD ?
SS2 DW ?
DW ?
_CR3 DD ?
EIP DD ?
EFLAGS DD ?
_EAX DD ?
_ECX DD ?
_EDX DD ?
_EBX DD ?
_ESP DD ?
_EBP DD ?
_ESI DD ?
_EDI DD ?
_ES DW ?
DW ?
_CS DW ?
DW ?
_SS DW ?
DW ?
_DS DW ?
DW ?
_FS DW ?
DW ?
_GS DW ?
DW ?
LDT DW ?
DW ?
DW ?
DW ?
IA32_TSS ENDS
; Create 2 TSS segments just after GDT
TssDescriptor LABEL BYTE
DW 0 ; PreviousTaskLink
DW 0 ; Reserved
DD 0 ; ESP0
DW 0 ; SS0
DW 0 ; Reserved
DD 0 ; ESP1
DW 0 ; SS1
DW 0 ; Reserved
DD 0 ; ESP2
DW 0 ; SS2
DW 0 ; Reserved
DD 0 ; CR3
DD 0 ; EIP
DD 0 ; EFLAGS
DD 0 ; EAX
DD 0 ; ECX
DD 0 ; EDX
DD 0 ; EBX
DD 0 ; ESP
DD 0 ; EBP
DD 0 ; ESI
DD 0 ; EDI
DW 0 ; ES
DW 0 ; Reserved
DW 0 ; CS
DW 0 ; Reserved
DW 0 ; SS
DW 0 ; Reserved
DW 0 ; DS
DW 0 ; Reserved
DW 0 ; FS
DW 0 ; Reserved
DW 0 ; GS
DW 0 ; Reserved
DW 0 ; LDT Selector
DW 0 ; Reserved
DW 0 ; T
DW 0 ; I/O Map Base
TSS_DESC_SIZE = $ - offset TssDescriptor
ExceptionTssDescriptor LABEL BYTE
DW 0 ; PreviousTaskLink
DW 0 ; Reserved
DD 0 ; ESP0
DW 0 ; SS0
DW 0 ; Reserved
DD 0 ; ESP1
DW 0 ; SS1
DW 0 ; Reserved
DD 0 ; ESP2
DW 0 ; SS2
DW 0 ; Reserved
DD 0 ; CR3
DD offset PFHandlerEntry ; EIP
DD 00000002 ; EFLAGS
DD 0 ; EAX
DD 0 ; ECX
DD 0 ; EDX
DD 0 ; EBX
DD 0 ; ESP
DD 0 ; EBP
DD 0 ; ESI
DD 0 ; EDI
DW DATA_SEL ; ES
DW 0 ; Reserved
DW CODE_SEL ; CS
DW 0 ; Reserved
DW DATA_SEL ; SS
DW 0 ; Reserved
DW DATA_SEL ; DS
DW 0 ; Reserved
DW DATA_SEL ; FS
DW 0 ; Reserved
DW DATA_SEL ; GS
DW 0 ; Reserved
DW 0 ; LDT Selector
DW 0 ; Reserved
DW 0 ; T
DW 0 ; I/O Map Base
gcPsd LABEL BYTE
DB 'TXTPSSIG'
DW PSD_SIZE
DW 1 ; Version
DD 0 ; LocalApicId
DB 05h ; Cr4Pse;Cr4Pae;Intel64Mode;ExecutionDisableOutsideSmrr
DB 0 ; BIOS to STM
DB 0 ; STM to BIOS
DB 0
DW CODE_SEL
DW DATA_SEL
DW DATA_SEL
DW DATA_SEL
DW 0
DW 0
DQ 0 ; SmmCr3
DQ _OnStmSetup
DQ _OnStmTeardown
DQ 0 ; SmmSmiHandlerRip - SMM guest entrypoint
DQ 0 ; SmmSmiHandlerRsp
DQ offset NullSeg
DD GDT_SIZE
DD 80010100h ; RequiredStmSmmRevId
DQ _OnException
DQ 0 ; ExceptionStack
DW DATA_SEL
DW 01Fh ; ExceptionFilter
DD 0
DQ offset gSmiMtrrs
DQ 0 ; BiosHwResourceRequirementsPtr
DQ 0 ; AcpiRsdp
DB 0 ; PhysicalAddressBits
PSD_SIZE = $ - offset gcPsd
gcSmiGdtr LABEL FWORD
DW GDT_SIZE - 1
DD offset NullSeg
gcSmiIdtr LABEL FWORD
DW IDT_SIZE - 1
DD offset _SmiIDT
_SmiIDT LABEL QWORD
REPEAT 32
DW 0 ; Offset 0:15
DW CODE_SEL ; Segment selector
DB 0 ; Unused
DB 8eh ; Interrupt Gate, Present
DW 0 ; Offset 16:31
ENDM
IDT_SIZE = $ - offset _SmiIDT
TaskGateDescriptor LABEL DWORD
DW 0 ; Reserved
DW EXCEPTION_TSS_SEL ; TSS Segment selector
DB 0 ; Reserved
DB 85h ; Task Gate, present, DPL = 0
DW 0 ; Reserved
.code
;------------------------------------------------------------------------------
; PageFaultIdtHandlerSmmProfile is the entry point page fault only
;
;
; Stack:
; +---------------------+
; + EFlags +
; +---------------------+
; + CS +
; +---------------------+
; + EIP +
; +---------------------+
; + Error Code +
; +---------------------+
; + Vector Number +
; +---------------------+
; + EBP +
; +---------------------+ <-- EBP
;
;
;------------------------------------------------------------------------------
PageFaultIdtHandlerSmmProfile PROC
push 0eh ; Page Fault
push ebp
mov ebp, esp
;
; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
; is 16-byte aligned
;
and esp, 0fffffff0h
sub esp, 12
;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
push eax
push ecx
push edx
push ebx
lea ecx, [ebp + 6 * 4]
push ecx ; ESP
push dword ptr [ebp] ; EBP
push esi
push edi
;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
mov eax, ss
push eax
movzx eax, word ptr [ebp + 4 * 4]
push eax
mov eax, ds
push eax
mov eax, es
push eax
mov eax, fs
push eax
mov eax, gs
push eax
;; UINT32 Eip;
mov eax, [ebp + 3 * 4]
push eax
;; UINT32 Gdtr[2], Idtr[2];
sub esp, 8
sidt [esp]
mov eax, [esp + 2]
xchg eax, [esp]
and eax, 0FFFFh
mov [esp+4], eax
sub esp, 8
sgdt [esp]
mov eax, [esp + 2]
xchg eax, [esp]
and eax, 0FFFFh
mov [esp+4], eax
;; UINT32 Ldtr, Tr;
xor eax, eax
str ax
push eax
sldt ax
push eax
;; UINT32 EFlags;
mov eax, [ebp + 5 * 4]
push eax
;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
mov eax, cr4
or eax, 208h
mov cr4, eax
push eax
mov eax, cr3
push eax
mov eax, cr2
push eax
xor eax, eax
push eax
mov eax, cr0
push eax
;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
mov eax, dr7
push eax
mov eax, dr6
push eax
mov eax, dr3
push eax
mov eax, dr2
push eax
mov eax, dr1
push eax
mov eax, dr0
push eax
;; FX_SAVE_STATE_IA32 FxSaveState;
sub esp, 512
mov edi, esp
db 0fh, 0aeh, 07h ;fxsave [edi]
; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
cld
;; UINT32 ExceptionData;
push dword ptr [ebp + 2 * 4]
;; call into exception handler
;; Prepare parameter and call
mov edx, esp
push edx
mov edx, dword ptr [ebp + 1 * 4]
push edx
;
; Call External Exception Handler
;
mov eax, SmiPFHandler
call eax
add esp, 8
;; UINT32 ExceptionData;
add esp, 4
;; FX_SAVE_STATE_IA32 FxSaveState;
mov esi, esp
db 0fh, 0aeh, 0eh ; fxrstor [esi]
add esp, 512
;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
;; Skip restoration of DRx registers to support debuggers
;; that set breakpoint in interrupt/exception context
add esp, 4 * 6
;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
pop eax
mov cr0, eax
add esp, 4 ; not for Cr1
pop eax
mov cr2, eax
pop eax
mov cr3, eax
pop eax
mov cr4, eax
;; UINT32 EFlags;
pop dword ptr [ebp + 5 * 4]
;; UINT32 Ldtr, Tr;
;; UINT32 Gdtr[2], Idtr[2];
;; Best not let anyone mess with these particular registers...
add esp, 24
;; UINT32 Eip;
pop dword ptr [ebp + 3 * 4]
;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
;; NOTE - modified segment registers could hang the debugger... We
;; could attempt to insulate ourselves against this possibility,
;; but that poses risks as well.
;;
pop gs
pop fs
pop es
pop ds
pop dword ptr [ebp + 4 * 4]
pop ss
;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
pop edi
pop esi
add esp, 4 ; not for ebp
add esp, 4 ; not for esp
pop ebx
pop edx
pop ecx
pop eax
mov esp, ebp
pop ebp
; Enable TF bit after page fault handler runs
bts dword ptr [esp + 16], 8 ; EFLAGS
add esp, 8 ; skip INT# & ErrCode
Return:
iretd
;
; Page Fault Exception Handler entry when SMM Stack Guard is enabled
; Executiot starts here after a task switch
;
PFHandlerEntry::
;
; Get this processor's TSS
;
sub esp, 8
sgdt [esp + 2]
mov eax, [esp + 4] ; GDT base
add esp, 8
mov ecx, [eax + TSS_SEL + 2]
shl ecx, 8
mov cl, [eax + TSS_SEL + 7]
ror ecx, 8 ; ecx = TSS base
mov ebp, esp
;
; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
; is 16-byte aligned
;
and esp, 0fffffff0h
sub esp, 12
;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
push (IA32_TSS ptr [ecx])._EAX
push (IA32_TSS ptr [ecx])._ECX
push (IA32_TSS ptr [ecx])._EDX
push (IA32_TSS ptr [ecx])._EBX
push (IA32_TSS ptr [ecx])._ESP
push (IA32_TSS ptr [ecx])._EBP
push (IA32_TSS ptr [ecx])._ESI
push (IA32_TSS ptr [ecx])._EDI
;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
movzx eax, (IA32_TSS ptr [ecx])._SS
push eax
movzx eax, (IA32_TSS ptr [ecx])._CS
push eax
movzx eax, (IA32_TSS ptr [ecx])._DS
push eax
movzx eax, (IA32_TSS ptr [ecx])._ES
push eax
movzx eax, (IA32_TSS ptr [ecx])._FS
push eax
movzx eax, (IA32_TSS ptr [ecx])._GS
push eax
;; UINT32 Eip;
push (IA32_TSS ptr [ecx]).EIP
;; UINT32 Gdtr[2], Idtr[2];
sub esp, 8
sidt [esp]
mov eax, [esp + 2]
xchg eax, [esp]
and eax, 0FFFFh
mov [esp+4], eax
sub esp, 8
sgdt [esp]
mov eax, [esp + 2]
xchg eax, [esp]
and eax, 0FFFFh
mov [esp+4], eax
;; UINT32 Ldtr, Tr;
mov eax, TSS_SEL
push eax
movzx eax, (IA32_TSS ptr [ecx]).LDT
push eax
;; UINT32 EFlags;
push (IA32_TSS ptr [ecx]).EFLAGS
;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
mov eax, cr4
or eax, 208h
mov cr4, eax
push eax
mov eax, cr3
push eax
mov eax, cr2
push eax
xor eax, eax
push eax
mov eax, cr0
push eax
;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
mov eax, dr7
push eax
mov eax, dr6
push eax
mov eax, dr3
push eax
mov eax, dr2
push eax
mov eax, dr1
push eax
mov eax, dr0
push eax
;; FX_SAVE_STATE_IA32 FxSaveState;
;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
;; when executing fxsave/fxrstor instruction
clts
sub esp, 512
mov edi, esp
db 0fh, 0aeh, 07h ;fxsave [edi]
; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
cld
;; UINT32 ExceptionData;
push dword ptr [ebp]
;; call into exception handler
mov ebx, ecx
mov eax, SmiPFHandler
;; Prepare parameter and call
mov edx, esp
push edx
mov edx, 14
push edx
;
; Call External Exception Handler
;
call eax
add esp, 8
mov ecx, ebx
;; UINT32 ExceptionData;
add esp, 4
;; FX_SAVE_STATE_IA32 FxSaveState;
mov esi, esp
db 0fh, 0aeh, 0eh ; fxrstor [esi]
add esp, 512
;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
;; Skip restoration of DRx registers to support debuggers
;; that set breakpoints in interrupt/exception context
add esp, 4 * 6
;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
pop eax
mov cr0, eax
add esp, 4 ; not for Cr1
pop eax
mov cr2, eax
pop eax
mov (IA32_TSS ptr [ecx])._CR3, eax
pop eax
mov cr4, eax
;; UINT32 EFlags;
pop (IA32_TSS ptr [ecx]).EFLAGS
;; UINT32 Ldtr, Tr;
;; UINT32 Gdtr[2], Idtr[2];
;; Best not let anyone mess with these particular registers...
add esp, 24
;; UINT32 Eip;
pop (IA32_TSS ptr [ecx]).EIP
;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
;; NOTE - modified segment registers could hang the debugger... We
;; could attempt to insulate ourselves against this possibility,
;; but that poses risks as well.
;;
pop eax
mov (IA32_TSS ptr [ecx])._GS, ax
pop eax
mov (IA32_TSS ptr [ecx])._FS, ax
pop eax
mov (IA32_TSS ptr [ecx])._ES, ax
pop eax
mov (IA32_TSS ptr [ecx])._DS, ax
pop eax
mov (IA32_TSS ptr [ecx])._CS, ax
pop eax
mov (IA32_TSS ptr [ecx])._SS, ax
;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
pop (IA32_TSS ptr [ecx])._EDI
pop (IA32_TSS ptr [ecx])._ESI
add esp, 4 ; not for ebp
add esp, 4 ; not for esp
pop (IA32_TSS ptr [ecx])._EBX
pop (IA32_TSS ptr [ecx])._EDX
pop (IA32_TSS ptr [ecx])._ECX
pop (IA32_TSS ptr [ecx])._EAX
mov esp, ebp
; Set single step DB# if SMM profile is enabled and page fault exception happens
cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0
jz @Done2
; Create return context for iretd in stub function
mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer
mov ebx, (IA32_TSS ptr [ecx]).EIP
mov [eax - 0ch], ebx ; create EIP in old stack
movzx ebx, (IA32_TSS ptr [ecx])._CS
mov [eax - 08h], ebx ; create CS in old stack
mov ebx, (IA32_TSS ptr [ecx]).EFLAGS
bts ebx, 8
mov [eax - 04h], ebx ; create eflags in old stack
mov eax, (IA32_TSS ptr [ecx])._ESP ; Get old stack pointer
sub eax, 0ch ; minus 12 byte
mov (IA32_TSS ptr [ecx])._ESP, eax ; Set new stack pointer
; Replace the EIP of interrupted task with stub function
mov eax, PageFaultStubFunction
mov (IA32_TSS ptr [ecx]).EIP, eax
; Jump to the iretd so next page fault handler as a task will start again after iretd.
@Done2:
add esp, 4 ; skip ErrCode
jmp Return
PageFaultIdtHandlerSmmProfile ENDP
PageFaultStubFunction PROC
;
; we need clean TS bit in CR0 to execute
; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
;
clts
iretd
PageFaultStubFunction ENDP
InitializeIDTSmmStackGuard PROC USES ebx
;
; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
; is a Task Gate Descriptor so that when a Page Fault Exception occurs,
; the processors can use a known good stack in case stack is ran out.
;
lea ebx, _SmiIDT + 14 * 8
lea edx, TaskGateDescriptor
mov eax, [edx]
mov [ebx], eax
mov eax, [edx + 4]
mov [ebx + 4], eax
ret
InitializeIDTSmmStackGuard ENDP
;------------------------------------------------------------------------------
; SMM Exception handlers
;------------------------------------------------------------------------------
_OnException PROC
mov ecx, esp
push ecx
call SmmStmExceptionHandler
add esp, 4
mov ebx, eax
mov eax, 4
DB 0fh, 01h, 0c1h ; VMCALL
jmp $
_OnException ENDP
_OnStmSetup PROC
call SmmStmSetup
rsm
_OnStmSetup ENDP
_OnStmTeardown PROC
call SmmStmTeardown
rsm
_OnStmTeardown ENDP
END

View File

@ -0,0 +1,96 @@
/** @file
SMM CPU misc functions for Ia32 arch specific.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
/**
Initialize Gdt for all processors.
@param[in] Cr3 CR3 value.
@param[out] GdtStepSize The step size for GDT table.
@return GdtBase for processor 0.
GdtBase for processor X is: GdtBase + (GdtStepSize * X)
**/
VOID *
InitGdt (
IN UINTN Cr3,
OUT UINTN *GdtStepSize
)
{
UINTN Index;
IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;
UINTN TssBase;
UINTN GdtTssTableSize;
UINT8 *GdtTssTables;
UINTN GdtTableStepSize;
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
//
// For IA32 SMM, if SMM Stack Guard feature is enabled, we use 2 TSS.
// in this case, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
// on each SMI entry.
//
//
// Enlarge GDT to contain 2 TSS descriptors
//
gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
ASSERT (GdtTssTables != NULL);
GdtTableStepSize = GdtTssTableSize;
for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE * 2);
//
// Fixup TSS descriptors
//
TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
TssBase += TSS_SIZE;
GdtDescriptor++;
GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
//
// Fixup TSS segments
//
// ESP as known good stack
//
*(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
*(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
}
} else {
//
// Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.
//
GdtTssTableSize = gcSmiGdtr.Limit + 1;
GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
ASSERT (GdtTssTables != NULL);
GdtTableStepSize = GdtTssTableSize;
for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1);
}
}
*GdtStepSize = GdtTableStepSize;
return GdtTssTables;
}

View File

@ -0,0 +1,84 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# SmmInit.S
#
# Abstract:
#
# Functions for relocating SMBASE's for all processors
#
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(gSmmCr0)
ASM_GLOBAL ASM_PFX(gSmmCr3)
ASM_GLOBAL ASM_PFX(gSmmCr4)
ASM_GLOBAL ASM_PFX(gcSmmInitTemplate)
ASM_GLOBAL ASM_PFX(gcSmmInitSize)
ASM_GLOBAL ASM_PFX(gSmmJmpAddr)
ASM_GLOBAL ASM_PFX(SmmRelocationSemaphoreComplete)
ASM_GLOBAL ASM_PFX(gSmmInitStack)
ASM_GLOBAL ASM_PFX(gcSmiInitGdtr)
.equ PROTECT_MODE_CS, 0x08
.equ PROTECT_MODE_DS, 0x20
.text
ASM_PFX(gcSmiInitGdtr):
.word 0
.quad 0
SmmStartup:
.byte 0x66,0xb8
ASM_PFX(gSmmCr3): .space 4
movl %eax, %cr3
.byte 0x67,0x66
lgdt %cs:(ASM_PFX(gcSmiInitGdtr) - SmmStartup)(%ebp)
.byte 0x66,0xb8
ASM_PFX(gSmmCr4): .space 4
movl %eax, %cr4
.byte 0x66,0xb8
ASM_PFX(gSmmCr0): .space 4
.byte 0xbf, PROTECT_MODE_DS, 0 # mov di, PROTECT_MODE_DS
movl %eax, %cr0
.byte 0x66,0xea # jmp far [ptr48]
ASM_PFX(gSmmJmpAddr): .long Start32bit
.word PROTECT_MODE_CS
Start32bit:
movl %edi,%ds
movl %edi,%es
movl %edi,%fs
movl %edi,%gs
movl %edi,%ss
.byte 0xbc # mov esp, imm32
ASM_PFX(gSmmInitStack): .space 4
call ASM_PFX(SmmInitHandler)
rsm
ASM_PFX(gcSmmInitTemplate):
_SmmInitTemplate:
.byte 0x66
movl $SmmStartup, %ebp
.byte 0x66, 0x81, 0xed, 0, 0, 3, 0 # sub ebp, 0x30000
jmp *%bp # jmp ebp actually
ASM_PFX(gcSmmInitSize): .word . - ASM_PFX(gcSmmInitTemplate)
ASM_PFX(SmmRelocationSemaphoreComplete):
pushl %eax
movl ASM_PFX(mRebasedFlag), %eax
movb $1, (%eax)
popl %eax
jmp *ASM_PFX(mSmmRelocationOriginalAddress)

View File

@ -0,0 +1,94 @@
;------------------------------------------------------------------------------ ;
; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
; SmmInit.Asm
;
; Abstract:
;
; Functions for relocating SMBASE's for all processors
;
;-------------------------------------------------------------------------------
.686p
.xmm
.model flat,C
SmmInitHandler PROTO C
EXTERNDEF C gSmmCr0:DWORD
EXTERNDEF C gSmmCr3:DWORD
EXTERNDEF C gSmmCr4:DWORD
EXTERNDEF C gcSmmInitTemplate:BYTE
EXTERNDEF C gcSmmInitSize:WORD
EXTERNDEF C gSmmJmpAddr:QWORD
EXTERNDEF C mRebasedFlag:PTR BYTE
EXTERNDEF C mSmmRelocationOriginalAddress:DWORD
EXTERNDEF C gSmmInitStack:DWORD
EXTERNDEF C gcSmiInitGdtr:FWORD
PROTECT_MODE_CS EQU 08h
PROTECT_MODE_DS EQU 20h
.code
gcSmiInitGdtr LABEL FWORD
DW 0
DQ 0
SmmStartup PROC
DB 66h, 0b8h
gSmmCr3 DD ?
mov cr3, eax
DB 67h, 66h
lgdt fword ptr cs:[ebp + (offset gcSmiInitGdtr - SmmStartup)]
DB 66h, 0b8h
gSmmCr4 DD ?
mov cr4, eax
DB 66h, 0b8h
gSmmCr0 DD ?
DB 0bfh, PROTECT_MODE_DS, 0 ; mov di, PROTECT_MODE_DS
mov cr0, eax
DB 66h, 0eah ; jmp far [ptr48]
gSmmJmpAddr LABEL QWORD
DD @32bit
DW PROTECT_MODE_CS
@32bit:
mov ds, edi
mov es, edi
mov fs, edi
mov gs, edi
mov ss, edi
DB 0bch ; mov esp, imm32
gSmmInitStack DD ?
call SmmInitHandler
rsm
SmmStartup ENDP
gcSmmInitTemplate LABEL BYTE
_SmmInitTemplate PROC
DB 66h
mov ebp, SmmStartup
DB 66h, 81h, 0edh, 00h, 00h, 03h, 00 ; sub ebp, 30000h
jmp bp ; jmp ebp actually
_SmmInitTemplate ENDP
gcSmmInitSize DW $ - gcSmmInitTemplate
SmmRelocationSemaphoreComplete PROC
push eax
mov eax, mRebasedFlag
mov byte ptr [eax], 1
pop eax
jmp [mSmmRelocationOriginalAddress]
SmmRelocationSemaphoreComplete ENDP
END

View File

@ -0,0 +1,80 @@
/** @file
IA-32 processor specific functions to enable SMM profile.
Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
#include "SmmProfileInternal.h"
/**
Create SMM page table for S3 path.
**/
VOID
InitSmmS3Cr3 (
VOID
)
{
mSmmS3ResumeState->SmmS3Cr3 = Gen4GPageTable (0, TRUE);
return ;
}
/**
Allocate pages for creating 4KB-page based on 2MB-page when page fault happens.
32-bit firmware does not need it.
**/
VOID
InitPagesForPFHandler (
VOID
)
{
}
/**
Update page table to map the memory correctly in order to make the instruction
which caused page fault execute successfully. And it also save the original page
table to be restored in single-step exception. 32-bit firmware does not need it.
@param PageTable PageTable Address.
@param PFAddress The memory address which caused page fault exception.
@param CpuIndex The index of the processor.
@param ErrorCode The Error code of exception.
@param IsValidPFAddress The flag indicates if SMM profile data need be added.
**/
VOID
RestorePageTableAbove4G (
UINT64 *PageTable,
UINT64 PFAddress,
UINTN CpuIndex,
UINTN ErrorCode,
BOOLEAN *IsValidPFAddress
)
{
}
/**
Clear TF in FLAGS.
@param SystemContext A pointer to the processor context when
the interrupt occurred on the processor.
**/
VOID
ClearTrapFlag (
IN OUT EFI_SYSTEM_CONTEXT SystemContext
)
{
SystemContext.SystemContextIa32->Eflags &= (UINTN) ~BIT8;
}

View File

@ -0,0 +1,97 @@
/** @file
IA-32 processor specific header file to enable SMM profile.
Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SMM_PROFILE_ARCH_H_
#define _SMM_PROFILE_ARCH_H_
#pragma pack (1)
typedef struct _MSR_DS_AREA_STRUCT {
UINT32 BTSBufferBase;
UINT32 BTSIndex;
UINT32 BTSAbsoluteMaximum;
UINT32 BTSInterruptThreshold;
UINT32 PEBSBufferBase;
UINT32 PEBSIndex;
UINT32 PEBSAbsoluteMaximum;
UINT32 PEBSInterruptThreshold;
UINT32 PEBSCounterReset[4];
UINT32 Reserved;
} MSR_DS_AREA_STRUCT;
typedef struct _BRANCH_TRACE_RECORD {
UINT32 LastBranchFrom;
UINT32 LastBranchTo;
UINT32 Rsvd0 : 4;
UINT32 BranchPredicted : 1;
UINT32 Rsvd1 : 27;
} BRANCH_TRACE_RECORD;
typedef struct _PEBS_RECORD {
UINT32 Eflags;
UINT32 LinearIP;
UINT32 Eax;
UINT32 Ebx;
UINT32 Ecx;
UINT32 Edx;
UINT32 Esi;
UINT32 Edi;
UINT32 Ebp;
UINT32 Esp;
} PEBS_RECORD;
#pragma pack ()
#define PHYSICAL_ADDRESS_MASK ((1ull << 32) - SIZE_4KB)
/**
Update page table to map the memory correctly in order to make the instruction
which caused page fault execute successfully. And it also save the original page
table to be restored in single-step exception. 32-bit firmware does not need it.
@param PageTable PageTable Address.
@param PFAddress The memory address which caused page fault exception.
@param CpuIndex The index of the processor.
@param ErrorCode The Error code of exception.
@param IsValidPFAddress The flag indicates if SMM profile data need be added.
**/
VOID
RestorePageTableAbove4G (
UINT64 *PageTable,
UINT64 PFAddress,
UINTN CpuIndex,
UINTN ErrorCode,
BOOLEAN *IsValidPFAddress
);
/**
Create SMM page table for S3 path.
**/
VOID
InitSmmS3Cr3 (
VOID
);
/**
Allocate pages for creating 4KB-page based on 2MB-page when page fault happens.
**/
VOID
InitPagesForPFHandler (
VOID
);
#endif // _SMM_PROFILE_ARCH_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,747 @@
/** @file
Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.
Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _CPU_PISMMCPUDXESMM_H_
#define _CPU_PISMMCPUDXESMM_H_
#include <PiSmm.h>
#include <Protocol/MpService.h>
#include <Protocol/SmmConfiguration.h>
#include <Protocol/SmmCpu.h>
#include <Protocol/SmmAccess2.h>
#include <Protocol/SmmReadyToLock.h>
#include <Protocol/SmmEndOfDxe.h>
#include <Protocol/SmmCpuService.h>
#include <Guid/AcpiS3Context.h>
#include <Guid/MsegSmram.h>
#include <Guid/Acpi.h>
#include <Library/BaseLib.h>
#include <Library/IoLib.h>
#include <Library/TimerLib.h>
#include <Library/SynchronizationLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PcdLib.h>
#include <Library/CacheMaintenanceLib.h>
#include <Library/MtrrLib.h>
#include <Library/SmmCpuPlatformHookLib.h>
#include <Library/SmmServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/DebugAgentLib.h>
#include <Library/HobLib.h>
#include <Library/LocalApicLib.h>
#include <Library/UefiCpuLib.h>
#include <Library/CpuExceptionHandlerLib.h>
#include <Library/ReportStatusCodeLib.h>
#include <Library/SmmCpuFeaturesLib.h>
#include <Library/PeCoffGetEntryPointLib.h>
#include <AcpiCpuData.h>
#include <CpuHotPlugData.h>
#include <Register/Cpuid.h>
#include <StmApi.h>
#include "CpuService.h"
#include "SmmProfile.h"
#include "SmmStm.h"
//
// MSRs required for configuration of SMM Code Access Check
//
#define EFI_MSR_SMM_MCA_CAP 0x17D
#define SMM_CODE_ACCESS_CHK_BIT BIT58
#define SMM_FEATURE_CONTROL_LOCK_BIT BIT0
#define SMM_CODE_CHK_EN_BIT BIT2
///
/// Page Table Entry
///
#define IA32_PG_P BIT0
#define IA32_PG_RW BIT1
#define IA32_PG_U BIT2
#define IA32_PG_WT BIT3
#define IA32_PG_CD BIT4
#define IA32_PG_A BIT5
#define IA32_PG_D BIT6
#define IA32_PG_PS BIT7
#define IA32_PG_PAT_2M BIT12
#define IA32_PG_PAT_4K IA32_PG_PS
#define IA32_PG_PMNT BIT62
#define IA32_PG_NX BIT63
#define PAGE_ATTRIBUTE_BITS (IA32_PG_RW | IA32_PG_P)
//
// Bits 1, 2, 5, 6 are reserved in the IA32 PAE PDPTE
// X64 PAE PDPTE does not have such restriction
//
#define IA32_PAE_PDPTE_ATTRIBUTE_BITS (IA32_PG_P)
//
// Size of Task-State Segment defined in IA32 Manual
//
#define TSS_SIZE 104
#define TSS_X64_IST1_OFFSET 36
#define TSS_IA32_CR3_OFFSET 28
#define TSS_IA32_ESP_OFFSET 56
//
// Code select value
//
#define PROTECT_MODE_CODE_SEGMENT 0x08
#define LONG_MODE_CODE_SEGMENT 0x38
//
// The size 0x20 must be bigger than
// the size of template code of SmmInit. Currently,
// the size of SmmInit requires the 0x16 Bytes buffer
// at least.
//
#define BACK_BUF_SIZE 0x20
#define EXCEPTION_VECTOR_NUMBER 0x20
#define INVALID_APIC_ID 0xFFFFFFFFFFFFFFFFULL
typedef UINT32 SMM_CPU_ARRIVAL_EXCEPTIONS;
#define ARRIVAL_EXCEPTION_BLOCKED 0x1
#define ARRIVAL_EXCEPTION_DELAYED 0x2
#define ARRIVAL_EXCEPTION_SMI_DISABLED 0x4
//
// Private structure for the SMM CPU module that is stored in DXE Runtime memory
// Contains the SMM Configuration Protocols that is produced.
// Contains a mix of DXE and SMM contents. All the fields must be used properly.
//
#define SMM_CPU_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('s', 'c', 'p', 'u')
typedef struct {
UINTN Signature;
EFI_HANDLE SmmCpuHandle;
EFI_PROCESSOR_INFORMATION *ProcessorInfo;
SMM_CPU_OPERATION *Operation;
UINTN *CpuSaveStateSize;
VOID **CpuSaveState;
EFI_SMM_RESERVED_SMRAM_REGION SmmReservedSmramRegion[1];
EFI_SMM_ENTRY_CONTEXT SmmCoreEntryContext;
EFI_SMM_ENTRY_POINT SmmCoreEntry;
EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration;
} SMM_CPU_PRIVATE_DATA;
extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate;
extern CPU_HOT_PLUG_DATA mCpuHotPlugData;
extern UINTN mMaxNumberOfCpus;
extern UINTN mNumberOfCpus;
extern BOOLEAN mRestoreSmmConfigurationInS3;
extern EFI_SMM_CPU_PROTOCOL mSmmCpu;
///
/// The mode of the CPU at the time an SMI occurs
///
extern UINT8 mSmmSaveStateRegisterLma;
//
// SMM CPU Protocol function prototypes.
//
/**
Read information from the CPU save state.
@param This EFI_SMM_CPU_PROTOCOL instance
@param Width The number of bytes to read from the CPU save state.
@param Register Specifies the CPU register to read form the save state.
@param CpuIndex Specifies the zero-based index of the CPU save state
@param Buffer Upon return, this holds the CPU register value read from the save state.
@retval EFI_SUCCESS The register was read from Save State
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
@retval EFI_INVALID_PARAMTER This or Buffer is NULL.
**/
EFI_STATUS
EFIAPI
SmmReadSaveState (
IN CONST EFI_SMM_CPU_PROTOCOL *This,
IN UINTN Width,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN CpuIndex,
OUT VOID *Buffer
);
/**
Write data to the CPU save state.
@param This EFI_SMM_CPU_PROTOCOL instance
@param Width The number of bytes to read from the CPU save state.
@param Register Specifies the CPU register to write to the save state.
@param CpuIndex Specifies the zero-based index of the CPU save state
@param Buffer Upon entry, this holds the new CPU register value.
@retval EFI_SUCCESS The register was written from Save State
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
@retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct
**/
EFI_STATUS
EFIAPI
SmmWriteSaveState (
IN CONST EFI_SMM_CPU_PROTOCOL *This,
IN UINTN Width,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN CpuIndex,
IN CONST VOID *Buffer
);
/**
Read a CPU Save State register on the target processor.
This function abstracts the differences that whether the CPU Save State register is in the
IA32 CPU Save State Map or X64 CPU Save State Map.
This function supports reading a CPU Save State register in SMBase relocation handler.
@param[in] CpuIndex Specifies the zero-based index of the CPU save state.
@param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
@param[in] Width The number of bytes to read from the CPU save state.
@param[out] Buffer Upon return, this holds the CPU register value read from the save state.
@retval EFI_SUCCESS The register was read from Save State.
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
@retval EFI_INVALID_PARAMTER This or Buffer is NULL.
**/
EFI_STATUS
EFIAPI
ReadSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
OUT VOID *Buffer
);
/**
Write value to a CPU Save State register on the target processor.
This function abstracts the differences that whether the CPU Save State register is in the
IA32 CPU Save State Map or X64 CPU Save State Map.
This function supports writing a CPU Save State register in SMBase relocation handler.
@param[in] CpuIndex Specifies the zero-based index of the CPU save state.
@param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
@param[in] Width The number of bytes to read from the CPU save state.
@param[in] Buffer Upon entry, this holds the new CPU register value.
@retval EFI_SUCCESS The register was written to Save State.
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
@retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct.
**/
EFI_STATUS
EFIAPI
WriteSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
IN CONST VOID *Buffer
);
//
//
//
typedef struct {
UINT32 Offset;
UINT16 Segment;
UINT16 Reserved;
} IA32_FAR_ADDRESS;
extern IA32_FAR_ADDRESS gSmmJmpAddr;
extern CONST UINT8 gcSmmInitTemplate[];
extern CONST UINT16 gcSmmInitSize;
extern UINT32 gSmmCr0;
extern UINT32 gSmmCr3;
extern UINT32 gSmmCr4;
extern UINTN gSmmInitStack;
/**
Semaphore operation for all processor relocate SMMBase.
**/
VOID
EFIAPI
SmmRelocationSemaphoreComplete (
VOID
);
///
/// The type of SMM CPU Information
///
typedef struct {
SPIN_LOCK Busy;
volatile EFI_AP_PROCEDURE Procedure;
volatile VOID *Parameter;
volatile UINT32 Run;
volatile BOOLEAN Present;
} SMM_CPU_DATA_BLOCK;
typedef enum {
SmmCpuSyncModeTradition,
SmmCpuSyncModeRelaxedAp,
SmmCpuSyncModeMax
} SMM_CPU_SYNC_MODE;
typedef struct {
//
// Pointer to an array. The array should be located immediately after this structure
// so that UC cache-ability can be set together.
//
SMM_CPU_DATA_BLOCK *CpuData;
volatile UINT32 Counter;
volatile UINT32 BspIndex;
volatile BOOLEAN InsideSmm;
volatile BOOLEAN AllCpusInSync;
volatile SMM_CPU_SYNC_MODE EffectiveSyncMode;
volatile BOOLEAN SwitchBsp;
volatile BOOLEAN *CandidateBsp;
} SMM_DISPATCHER_MP_SYNC_DATA;
typedef struct {
SPIN_LOCK SpinLock;
UINT32 MsrIndex;
} MP_MSR_LOCK;
#define SMM_PSD_OFFSET 0xfb00
extern IA32_DESCRIPTOR gcSmiGdtr;
extern IA32_DESCRIPTOR gcSmiIdtr;
extern VOID *gcSmiIdtrPtr;
extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR gcPsd;
extern UINT64 gPhyMask;
extern ACPI_CPU_DATA mAcpiCpuData;
extern SMM_DISPATCHER_MP_SYNC_DATA *mSmmMpSyncData;
extern VOID *mGdtForAp;
extern VOID *mIdtForAp;
extern VOID *mMachineCheckHandlerForAp;
extern UINTN mSmmStackArrayBase;
extern UINTN mSmmStackArrayEnd;
extern UINTN mSmmStackSize;
extern EFI_SMM_CPU_SERVICE_PROTOCOL mSmmCpuService;
extern IA32_DESCRIPTOR gcSmiInitGdtr;
/**
Create 4G PageTable in SMRAM.
@param ExtraPages Additional page numbers besides for 4G memory
@param Is32BitPageTable Whether the page table is 32-bit PAE
@return PageTable Address
**/
UINT32
Gen4GPageTable (
IN UINTN ExtraPages,
IN BOOLEAN Is32BitPageTable
);
/**
Initialize global data for MP synchronization.
@param Stacks Base address of SMI stack buffer for all processors.
@param StackSize Stack size for each processor in SMM.
**/
UINT32
InitializeMpServiceData (
IN VOID *Stacks,
IN UINTN StackSize
);
/**
Initialize Timer for SMM AP Sync.
**/
VOID
InitializeSmmTimer (
VOID
);
/**
Start Timer for SMM AP Sync.
**/
UINT64
EFIAPI
StartSyncTimer (
VOID
);
/**
Check if the SMM AP Sync timer is timeout.
@param Timer The start timer from the begin.
**/
BOOLEAN
EFIAPI
IsSyncTimerTimeout (
IN UINT64 Timer
);
/**
Initialize IDT for SMM Stack Guard.
**/
VOID
EFIAPI
InitializeIDTSmmStackGuard (
VOID
);
/**
Initialize Gdt for all processors.
@param[in] Cr3 CR3 value.
@param[out] GdtStepSize The step size for GDT table.
@return GdtBase for processor 0.
GdtBase for processor X is: GdtBase + (GdtStepSize * X)
**/
VOID *
InitGdt (
IN UINTN Cr3,
OUT UINTN *GdtStepSize
);
/**
Register the SMM Foundation entry point.
@param This Pointer to EFI_SMM_CONFIGURATION_PROTOCOL instance
@param SmmEntryPoint SMM Foundation EntryPoint
@retval EFI_SUCCESS Successfully to register SMM foundation entry point
**/
EFI_STATUS
EFIAPI
RegisterSmmEntry (
IN CONST EFI_SMM_CONFIGURATION_PROTOCOL *This,
IN EFI_SMM_ENTRY_POINT SmmEntryPoint
);
/**
Create PageTable for SMM use.
@return PageTable Address
**/
UINT32
SmmInitPageTable (
VOID
);
/**
Schedule a procedure to run on the specified CPU.
@param Procedure The address of the procedure to run
@param CpuIndex Target CPU number
@param ProcArguments The parameter to pass to the procedure
@retval EFI_INVALID_PARAMETER CpuNumber not valid
@retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
@retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM
@retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy
@retval EFI_SUCCESS - The procedure has been successfully scheduled
**/
EFI_STATUS
EFIAPI
SmmStartupThisAp (
IN EFI_AP_PROCEDURE Procedure,
IN UINTN CpuIndex,
IN OUT VOID *ProcArguments OPTIONAL
);
/**
Schedule a procedure to run on the specified CPU in a blocking fashion.
@param Procedure The address of the procedure to run
@param CpuIndex Target CPU Index
@param ProcArguments The parameter to pass to the procedure
@retval EFI_INVALID_PARAMETER CpuNumber not valid
@retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
@retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM
@retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy
@retval EFI_SUCCESS The procedure has been successfully scheduled
**/
EFI_STATUS
EFIAPI
SmmBlockingStartupThisAp (
IN EFI_AP_PROCEDURE Procedure,
IN UINTN CpuIndex,
IN OUT VOID *ProcArguments OPTIONAL
);
/**
Initialize MP synchronization data.
**/
VOID
EFIAPI
InitializeMpSyncData (
VOID
);
/**
Find out SMRAM information including SMRR base and SMRR size.
@param SmrrBase SMRR base
@param SmrrSize SMRR size
**/
VOID
FindSmramInfo (
OUT UINT32 *SmrrBase,
OUT UINT32 *SmrrSize
);
/**
The function is invoked before SMBASE relocation in S3 path to restores CPU status.
The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
and restores MTRRs for both BSP and APs.
**/
VOID
EarlyInitializeCpu (
VOID
);
/**
The function is invoked after SMBASE relocation in S3 path to restores CPU status.
The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
data saved by normal boot path for both BSP and APs.
**/
VOID
InitializeCpu (
VOID
);
/**
Page Fault handler for SMM use.
@param InterruptType Defines the type of interrupt or exception that
occurred on the processor.This parameter is processor architecture specific.
@param SystemContext A pointer to the processor context when
the interrupt occurred on the processor.
**/
VOID
EFIAPI
SmiPFHandler (
IN EFI_EXCEPTION_TYPE InterruptType,
IN EFI_SYSTEM_CONTEXT SystemContext
);
/**
Perform the remaining tasks.
**/
VOID
PerformRemainingTasks (
VOID
);
/**
Perform the pre tasks.
**/
VOID
PerformPreTasks (
VOID
);
/**
Initialize MSR spin lock by MSR index.
@param MsrIndex MSR index value.
**/
VOID
InitMsrSpinLockByIndex (
IN UINT32 MsrIndex
);
/**
Hook return address of SMM Save State so that semaphore code
can be executed immediately after AP exits SMM to indicate to
the BSP that an AP has exited SMM after SMBASE relocation.
@param[in] CpuIndex The processor index.
@param[in] RebasedFlag A pointer to a flag that is set to TRUE
immediately after AP exits SMM.
**/
VOID
SemaphoreHook (
IN UINTN CpuIndex,
IN volatile BOOLEAN *RebasedFlag
);
/**
Configure SMM Code Access Check feature for all processors.
SMM Feature Control MSR will be locked after configuration.
**/
VOID
ConfigSmmCodeAccessCheck (
VOID
);
/**
Hook the code executed immediately after an RSM instruction on the currently
executing CPU. The mode of code executed immediately after RSM must be
detected, and the appropriate hook must be selected. Always clear the auto
HALT restart flag if it is set.
@param[in] CpuIndex The processor index for the currently
executing CPU.
@param[in] CpuState Pointer to SMRAM Save State Map for the
currently executing CPU.
@param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
32-bit mode from 64-bit SMM.
@param[in] NewInstructionPointer Instruction pointer to use if resuming to
same mode as SMM.
@retval The value of the original instruction pointer before it was hooked.
**/
UINT64
EFIAPI
HookReturnFromSmm (
IN UINTN CpuIndex,
SMRAM_SAVE_STATE_MAP *CpuState,
UINT64 NewInstructionPointer32,
UINT64 NewInstructionPointer
);
/**
Get the size of the SMI Handler in bytes.
@retval The size, in bytes, of the SMI Handler.
**/
UINTN
EFIAPI
GetSmiHandlerSize (
VOID
);
/**
Get the offset of the native SMI Handler.
@retval The offset of the native SMI Handler.
**/
UINTN
EFIAPI
GetSmiHandlerOffset (
VOID
);
/**
Install the SMI handler for the CPU specified by CpuIndex. This function
is called by the CPU that was elected as monarch during System Management
Mode initialization.
@param[in] CpuIndex The index of the CPU to install the custom SMI handler.
The value must be between 0 and the NumberOfCpus field
in the System Management System Table (SMST).
@param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
@param[in] SmiStack The stack to use when an SMI is processed by the
the CPU specified by CpuIndex.
@param[in] StackSize The size, in bytes, if the stack used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtBase The base address of the GDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtBase The base address of the IDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] Cr3 The base address of the page tables to use when an SMI
is processed by the CPU specified by CpuIndex.
**/
VOID
EFIAPI
InstallSmiHandler (
IN UINTN CpuIndex,
IN UINT32 SmBase,
IN VOID *SmiStack,
IN UINTN StackSize,
IN UINTN GdtBase,
IN UINTN GdtSize,
IN UINTN IdtBase,
IN UINTN IdtSize,
IN UINT32 Cr3
);
/**
Search module name by input IP address and output it.
@param CallerIpAddress Caller instruction pointer.
**/
VOID
DumpModuleInfoByIp (
IN UINTN CallerIpAddress
);
/**
This API provides a way to allocate memory for page table.
This API can be called more once to allocate memory for page tables.
Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
is returned. If there is not enough memory remaining to satisfy the request, then NULL is
returned.
@param Pages The number of 4 KB pages to allocate.
@return A pointer to the allocated buffer or NULL if allocation fails.
**/
VOID *
AllocatePageTableMemory (
IN UINTN Pages
);
#endif

View File

@ -0,0 +1,170 @@
## @file
# CPU SMM driver.
#
# This SMM driver performs SMM initialization, deploy SMM Entry Vector,
# provides CPU specific services in SMM.
#
# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = PiSmmCpuDxeSmmStm
MODULE_UNI_FILE = PiSmmCpuDxeSmm.uni
FILE_GUID = A3FF0EF5-0C28-42f5-B544-8C7DE1E80014
MODULE_TYPE = DXE_SMM_DRIVER
VERSION_STRING = 1.0
PI_SPECIFICATION_VERSION = 0x0001000A
ENTRY_POINT = PiCpuSmmEntry
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
PiSmmCpuDxeSmm.c
PiSmmCpuDxeSmm.h
MpService.c
SyncTimer.c
CpuS3.c
CpuService.c
CpuService.h
SmmProfile.c
SmmProfile.h
SmmProfileInternal.h
SmramSaveState.c
SmmStm.c
SmmStm.h
[Sources.Ia32]
Ia32/Semaphore.c
Ia32/PageTbl.c
Ia32/SmmFuncsArch.c
Ia32/SmmProfileArch.c
Ia32/SmmProfileArch.h
Ia32/SmmInit.asm | MSFT
Ia32/SmiEntry.asm | MSFT
Ia32/SmiException.asm | MSFT
Ia32/MpFuncs.asm | MSFT
Ia32/SmmInit.asm | INTEL
Ia32/SmiEntry.asm | INTEL
Ia32/SmiException.asm | INTEL
Ia32/MpFuncs.asm | INTEL
Ia32/SmmInit.S | GCC
Ia32/SmiEntry.S | GCC
Ia32/SmiException.S | GCC
Ia32/MpFuncs.S | GCC
[Sources.X64]
X64/Semaphore.c
X64/PageTbl.c
X64/SmmFuncsArch.c
X64/SmmProfileArch.c
X64/SmmProfileArch.h
X64/SmmInit.asm | MSFT
X64/SmiEntry.asm | MSFT
X64/SmiException.asm | MSFT
X64/MpFuncs.asm | MSFT
X64/SmmInit.asm | INTEL
X64/SmiEntry.asm | INTEL
X64/SmiException.asm | INTEL
X64/MpFuncs.asm | INTEL
X64/SmmInit.S | GCC
X64/SmiEntry.S | GCC
X64/SmiException.S | GCC
X64/MpFuncs.S | GCC
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
StmCpuPkg/StmCpuPkg.dec
UefiCpuPkg/UefiCpuPkg.dec
[LibraryClasses]
UefiDriverEntryPoint
UefiRuntimeServicesTableLib
CacheMaintenanceLib
PcdLib
DebugLib
BaseLib
SynchronizationLib
BaseMemoryLib
MtrrLib
IoLib
TimerLib
SmmServicesTableLib
MemoryAllocationLib
DebugAgentLib
HobLib
PciLib
LocalApicLib
UefiCpuLib
SmmCpuPlatformHookLib
CpuExceptionHandlerLib
UefiLib
DxeServicesTableLib
CpuLib
ReportStatusCodeLib
SmmCpuFeaturesLib
PeCoffGetEntryPointLib
[Protocols]
gEfiSmmAccess2ProtocolGuid ## CONSUMES
gEfiMpServiceProtocolGuid ## CONSUMES
gEfiSmmConfigurationProtocolGuid ## PRODUCES
gEfiSmmCpuProtocolGuid ## PRODUCES
gEfiSmmReadyToLockProtocolGuid ## NOTIFY
gEfiSmmEndOfDxeProtocolGuid ## SOMETIMES_CONSUMES
gEfiSmmCpuServiceProtocolGuid ## PRODUCES
gEfiSmMonitorInitProtocolGuid ## SOMETIMES_PRODUCES
[Guids]
gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is used for S3 boot.
gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"SmmProfileData"
gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ## SystemTable
gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable
gMsegSmramGuid ## SOMETIMES_CONSUMES ## HOB
[FeaturePcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmDebug ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmBlockStartupThisAp ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileEnable ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileRingBuffer ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmFeatureControlMsrLock ## CONSUMES
gStmCpuPkgTokenSpaceGuid.PcdCpuStmSupport ## CONSUMES
[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## SOMETIMES_CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileSize ## SOMETIMES_CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmApSyncTimeout ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress ## SOMETIMES_CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress ## SOMETIMES_PRODUCES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmCodeAccessCheckEnable ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode ## CONSUMES
gStmCpuPkgTokenSpaceGuid.PcdCpuMsegSize ## SOMETIMES_CONSUMES
gStmCpuPkgTokenSpaceGuid.PcdCpuSmmStmExceptionStackSize ## SOMETIMES_CONSUMES
[Depex]
gEfiMpServiceProtocolGuid
[UserExtensions.TianoCore."ExtraFiles"]
PiSmmCpuDxeSmmExtra.uni

View File

@ -0,0 +1,21 @@
// /** @file
// CPU SMM driver.
//
// This SMM driver performs SMM initialization, deploy SMM Entry Vector,
// provides CPU specific services in SMM.
//
// Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
//
// This program and the accompanying materials are
// licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "CPU SMM driver"
#string STR_MODULE_DESCRIPTION #language en-US "This SMM driver performs SMM initialization, deploys SMM Entry Vector, and provides CPU-specific services in SMM."

View File

@ -0,0 +1,18 @@
// /** @file
// PiSmmCpuDxeSmm Localized Strings and Content
//
// Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
//
// This program and the accompanying materials are
// licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
// **/
#string STR_PROPERTIES_MODULE_NAME
#language en-US
"Processor SMM Initialization DXE Driver"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
/** @file
SMM profile header file.
Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SMM_PROFILE_H_
#define _SMM_PROFILE_H_
#include "SmmProfileInternal.h"
///
/// MSR Register Index
///
#define MSR_IA32_MISC_ENABLE 0x1A0
#define B_XD_DISABLE_BIT BIT34
//
// External functions
//
/**
Initialize processor environment for SMM profile.
@param CpuIndex The index of the processor.
**/
VOID
ActivateSmmProfile (
IN UINTN CpuIndex
);
/**
Initialize SMM profile in SMM CPU entry point.
@param[in] Cr3 The base address of the page tables to use in SMM.
**/
VOID
InitSmmProfile (
UINT32 Cr3
);
/**
Increase SMI number in each SMI entry.
**/
VOID
SmmProfileRecordSmiNum (
VOID
);
/**
The Page fault handler to save SMM profile data.
@param Rip The RIP when exception happens.
@param ErrorCode The Error code of exception.
**/
VOID
SmmProfilePFHandler (
UINTN Rip,
UINTN ErrorCode
);
/**
Updates page table to make some memory ranges (like system memory) absent
and make some memory ranges (like MMIO) present and execute disable. It also
update 2MB-page to 4KB-page for some memory ranges.
**/
VOID
SmmProfileStart (
VOID
);
/**
Page fault IDT handler for SMM Profile.
**/
VOID
EFIAPI
PageFaultIdtHandlerSmmProfile (
VOID
);
/**
Check if XD feature is supported by a processor.
@param[in,out] Buffer The pointer to private data buffer.
**/
VOID
EFIAPI
CheckFeatureSupported (
IN OUT VOID *Buffer
);
/**
Enable XD feature.
**/
VOID
ActivateXd (
VOID
);
/**
Update page table according to protected memory ranges and the 4KB-page mapped memory ranges.
**/
VOID
InitPaging (
VOID
);
/**
Check if XD and BTS features are supported by all processors.
**/
VOID
CheckProcessorFeature (
VOID
);
extern BOOLEAN mXdSupported;
extern BOOLEAN mXdEnabled;
#endif // _SMM_PROFILE_H_

View File

@ -0,0 +1,172 @@
/** @file
SMM profile internal header file.
Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SMM_PROFILE_INTERNAL_H_
#define _SMM_PROFILE_INTERNAL_H_
#include <Guid/GlobalVariable.h>
#include <Guid/Acpi.h>
#include <Protocol/SmmReadyToLock.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/CpuLib.h>
#include <IndustryStandard/Acpi.h>
#include "SmmProfileArch.h"
//
// Configure the SMM_PROFILE DTS region size
//
#define SMM_PROFILE_DTS_SIZE (4 * 1024 * 1024) // 4M
#define MAX_PF_PAGE_COUNT 0x2
#define PEBS_RECORD_NUMBER 0x2
#define MAX_PF_ENTRY_COUNT 10
//
// This MACRO just enable unit test for the profile
// Please disable it.
//
#define IA32_PF_EC_P (1u << 0)
#define IA32_PF_EC_WR (1u << 1)
#define IA32_PF_EC_US (1u << 2)
#define IA32_PF_EC_RSVD (1u << 3)
#define IA32_PF_EC_ID (1u << 4)
#define SMM_PROFILE_NAME L"SmmProfileData"
//
// CPU generic definition
//
#define CPUID1_EDX_XD_SUPPORT 0x100000
#define MSR_EFER 0xc0000080
#define MSR_EFER_XD 0x800
#define CPUID1_EDX_BTS_AVAILABLE 0x200000
#define DR6_SINGLE_STEP 0x4000
#define RFLAG_TF 0x100
#define MSR_DEBUG_CTL 0x1D9
#define MSR_DEBUG_CTL_LBR 0x1
#define MSR_DEBUG_CTL_TR 0x40
#define MSR_DEBUG_CTL_BTS 0x80
#define MSR_DEBUG_CTL_BTINT 0x100
#define MSR_LASTBRANCH_TOS 0x1C9
#define MSR_LER_FROM_LIP 0x1DD
#define MSR_LER_TO_LIP 0x1DE
#define MSR_DS_AREA 0x600
typedef struct {
EFI_PHYSICAL_ADDRESS Base;
EFI_PHYSICAL_ADDRESS Top;
} MEMORY_RANGE;
typedef struct {
MEMORY_RANGE Range;
BOOLEAN Present;
BOOLEAN Nx;
} MEMORY_PROTECTION_RANGE;
typedef struct {
UINT64 HeaderSize;
UINT64 MaxDataEntries;
UINT64 MaxDataSize;
UINT64 CurDataEntries;
UINT64 CurDataSize;
UINT64 TsegStart;
UINT64 TsegSize;
UINT64 NumSmis;
UINT64 NumCpus;
} SMM_PROFILE_HEADER;
typedef struct {
UINT64 SmiNum;
UINT64 CpuNum;
UINT64 ApicId;
UINT64 ErrorCode;
UINT64 Instruction;
UINT64 Address;
UINT64 SmiCmd;
} SMM_PROFILE_ENTRY;
extern SMM_S3_RESUME_STATE *mSmmS3ResumeState;
extern UINTN gSmiExceptionHandlers[];
extern BOOLEAN mXdSupported;
extern UINTN *mPFEntryCount;
extern UINT64 (*mLastPFEntryValue)[MAX_PF_ENTRY_COUNT];
extern UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT];
//
// Internal functions
//
/**
Update IDT table to replace page fault handler and INT 1 handler.
**/
VOID
InitIdtr (
VOID
);
/**
Check if the memory address will be mapped by 4KB-page.
@param Address The address of Memory.
**/
BOOLEAN
IsAddressSplit (
IN EFI_PHYSICAL_ADDRESS Address
);
/**
Check if the memory address will be mapped by 4KB-page.
@param Address The address of Memory.
@param Nx The flag indicates if the memory is execute-disable.
**/
BOOLEAN
IsAddressValid (
IN EFI_PHYSICAL_ADDRESS Address,
IN BOOLEAN *Nx
);
/**
Page Fault handler for SMM use.
**/
VOID
SmiDefaultPFHandler (
VOID
);
/**
Clear TF in FLAGS.
@param SystemContext A pointer to the processor context when
the interrupt occurred on the processor.
**/
VOID
ClearTrapFlag (
IN OUT EFI_SYSTEM_CONTEXT SystemContext
);
#endif // _SMM_PROFILE_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
/** @file
SMM STM support
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SMM_STM_H_
#define _SMM_STM_H_
#include <Protocol/SmMonitorInit.h>
#define IA32_VMX_BASIC_MSR_INDEX 0x480
#define IA32_VMX_MISC_MSR_INDEX 0x485
#define IA32_SMM_MONITOR_CTL_MSR_INDEX 0x9B
#define IA32_SMM_MONITOR_VALID BIT0
/**
Get STM state.
@return STM state
**/
EFI_SM_MONITOR_STATE
EFIAPI
GetMonitorState (
VOID
);
/**
Load STM image to MSEG.
@param StmImage STM image
@param StmImageSize STM image size
@retval EFI_SUCCESS Load STM to MSEG successfully
@retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
**/
EFI_STATUS
EFIAPI
LoadMonitor (
IN EFI_PHYSICAL_ADDRESS StmImage,
IN UINTN StmImageSize
);
/**
Add resources in list to database. Allocate new memory areas as needed.
@param ResourceList A pointer to resource list to be added
@param NumEntries Optional number of entries.
If 0, list must be terminated by END_OF_RESOURCES.
@retval EFI_SUCCESS If resources are added
@retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
@retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
**/
EFI_STATUS
EFIAPI
AddPiResource (
IN STM_RSC *ResourceList,
IN UINT32 NumEntries OPTIONAL
);
/**
Delete resources in list to database.
@param ResourceList A pointer to resource list to be deleted
NULL means delete all resources.
@param NumEntries Optional number of entries.
If 0, list must be terminated by END_OF_RESOURCES.
@retval EFI_SUCCESS If resources are deleted
@retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
**/
EFI_STATUS
EFIAPI
DeletePiResource (
IN STM_RSC *ResourceList,
IN UINT32 NumEntries OPTIONAL
);
/**
Get BIOS resources.
@param ResourceList A pointer to resource list to be filled
@param ResourceSize On input it means size of resource list input.
On output it means size of resource list filled,
or the size of resource list to be filled if size of too small.
@retval EFI_SUCCESS If resources are returned.
@retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
**/
EFI_STATUS
EFIAPI
GetPiResource (
OUT STM_RSC *ResourceList,
IN OUT UINT32 *ResourceSize
);
/**
This functin initialize STM configuration table.
**/
VOID
StmSmmConfigurationTableInit (
VOID
);
/**
This function notify STM resource change.
@param StmResource BIOS STM resource
**/
VOID
NotifyStmResourceChange (
IN VOID *StmResource
);
/**
This function return BIOS STM resource.
@return BIOS STM resource
**/
VOID *
GetStmResource (
VOID
);
#endif

View File

@ -0,0 +1,722 @@
/** @file
Provides services to access SMRAM Save State Map
Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiSmm.h>
#include <Library/SmmCpuFeaturesLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/SmmServicesTableLib.h>
#include <Library/DebugLib.h>
#include <Register/Cpuid.h>
#include <Register/SmramSaveStateMap.h>
//
// EFER register LMA bit
//
#define LMA BIT10
///
/// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
///
#define SMM_CPU_OFFSET(Field) OFFSET_OF (SMRAM_SAVE_STATE_MAP, Field)
///
/// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE
///
#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
///
/// Structure used to describe a range of registers
///
typedef struct {
EFI_SMM_SAVE_STATE_REGISTER Start;
EFI_SMM_SAVE_STATE_REGISTER End;
UINTN Length;
} CPU_SMM_SAVE_STATE_REGISTER_RANGE;
///
/// Structure used to build a lookup table to retrieve the widths and offsets
/// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value
///
#define SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX 1
#define SMM_SAVE_STATE_REGISTER_IOMISC_INDEX 2
#define SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX 3
#define SMM_SAVE_STATE_REGISTER_MAX_INDEX 4
typedef struct {
UINT8 Width32;
UINT8 Width64;
UINT16 Offset32;
UINT16 Offset64Lo;
UINT16 Offset64Hi;
BOOLEAN Writeable;
} CPU_SMM_SAVE_STATE_LOOKUP_ENTRY;
///
/// Structure used to build a lookup table for the IOMisc width information
///
typedef struct {
UINT8 Width;
EFI_SMM_SAVE_STATE_IO_WIDTH IoWidth;
} CPU_SMM_SAVE_STATE_IO_WIDTH;
///
/// Variables from SMI Handler
///
extern UINT32 gSmbase;
extern volatile UINT32 gSmiStack;
extern UINT32 gSmiCr3;
extern volatile UINT8 gcSmiHandlerTemplate[];
extern CONST UINT16 gcSmiHandlerSize;
extern CONST UINT16 gcSmiHandlerOffset;
//
// Variables used by SMI Handler
//
IA32_DESCRIPTOR gSmiHandlerIdtr;
///
/// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER
/// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
///
CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = {
SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_GDTBASE, EFI_SMM_SAVE_STATE_REGISTER_LDTINFO),
SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_ES, EFI_SMM_SAVE_STATE_REGISTER_RIP),
SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_RFLAGS, EFI_SMM_SAVE_STATE_REGISTER_CR4),
{ (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0, 0 }
};
///
/// Lookup table used to retrieve the widths and offsets associated with each
/// supported EFI_SMM_SAVE_STATE_REGISTER value
///
CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = {
{0, 0, 0, 0, 0, FALSE}, // Reserved
//
// Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.
//
{4, 4, SMM_CPU_OFFSET (x86.SMMRevId) , SMM_CPU_OFFSET (x64.SMMRevId) , 0 , FALSE}, // SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX = 1
{4, 4, SMM_CPU_OFFSET (x86.IOMisc) , SMM_CPU_OFFSET (x64.IOMisc) , 0 , FALSE}, // SMM_SAVE_STATE_REGISTER_IOMISC_INDEX = 2
{4, 8, SMM_CPU_OFFSET (x86.IOMemAddr) , SMM_CPU_OFFSET (x64.IOMemAddr) , SMM_CPU_OFFSET (x64.IOMemAddr) + 4, FALSE}, // SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX = 3
//
// CPU Save State registers defined in PI SMM CPU Protocol.
//
{0, 8, 0 , SMM_CPU_OFFSET (x64.GdtBaseLoDword) , SMM_CPU_OFFSET (x64.GdtBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4
{0, 8, 0 , SMM_CPU_OFFSET (x64.IdtBaseLoDword) , SMM_CPU_OFFSET (x64.IdtBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5
{0, 8, 0 , SMM_CPU_OFFSET (x64.LdtBaseLoDword) , SMM_CPU_OFFSET (x64.LdtBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6
{0, 0, 0 , 0 , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
{0, 0, 0 , 0 , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
{0, 0, 0 , 0 , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
{0, 0, 0 , 0 , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10
{4, 4, SMM_CPU_OFFSET (x86._ES) , SMM_CPU_OFFSET (x64._ES) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20
{4, 4, SMM_CPU_OFFSET (x86._CS) , SMM_CPU_OFFSET (x64._CS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21
{4, 4, SMM_CPU_OFFSET (x86._SS) , SMM_CPU_OFFSET (x64._SS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22
{4, 4, SMM_CPU_OFFSET (x86._DS) , SMM_CPU_OFFSET (x64._DS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23
{4, 4, SMM_CPU_OFFSET (x86._FS) , SMM_CPU_OFFSET (x64._FS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24
{4, 4, SMM_CPU_OFFSET (x86._GS) , SMM_CPU_OFFSET (x64._GS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25
{0, 4, 0 , SMM_CPU_OFFSET (x64._LDTR) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
{4, 4, SMM_CPU_OFFSET (x86._TR) , SMM_CPU_OFFSET (x64._TR) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27
{4, 8, SMM_CPU_OFFSET (x86._DR7) , SMM_CPU_OFFSET (x64._DR7) , SMM_CPU_OFFSET (x64._DR7) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28
{4, 8, SMM_CPU_OFFSET (x86._DR6) , SMM_CPU_OFFSET (x64._DR6) , SMM_CPU_OFFSET (x64._DR6) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29
{0, 8, 0 , SMM_CPU_OFFSET (x64._R8) , SMM_CPU_OFFSET (x64._R8) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30
{0, 8, 0 , SMM_CPU_OFFSET (x64._R9) , SMM_CPU_OFFSET (x64._R9) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31
{0, 8, 0 , SMM_CPU_OFFSET (x64._R10) , SMM_CPU_OFFSET (x64._R10) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32
{0, 8, 0 , SMM_CPU_OFFSET (x64._R11) , SMM_CPU_OFFSET (x64._R11) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33
{0, 8, 0 , SMM_CPU_OFFSET (x64._R12) , SMM_CPU_OFFSET (x64._R12) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34
{0, 8, 0 , SMM_CPU_OFFSET (x64._R13) , SMM_CPU_OFFSET (x64._R13) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35
{0, 8, 0 , SMM_CPU_OFFSET (x64._R14) , SMM_CPU_OFFSET (x64._R14) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36
{0, 8, 0 , SMM_CPU_OFFSET (x64._R15) , SMM_CPU_OFFSET (x64._R15) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37
{4, 8, SMM_CPU_OFFSET (x86._EAX) , SMM_CPU_OFFSET (x64._RAX) , SMM_CPU_OFFSET (x64._RAX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38
{4, 8, SMM_CPU_OFFSET (x86._EBX) , SMM_CPU_OFFSET (x64._RBX) , SMM_CPU_OFFSET (x64._RBX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39
{4, 8, SMM_CPU_OFFSET (x86._ECX) , SMM_CPU_OFFSET (x64._RCX) , SMM_CPU_OFFSET (x64._RCX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RCX = 40
{4, 8, SMM_CPU_OFFSET (x86._EDX) , SMM_CPU_OFFSET (x64._RDX) , SMM_CPU_OFFSET (x64._RDX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41
{4, 8, SMM_CPU_OFFSET (x86._ESP) , SMM_CPU_OFFSET (x64._RSP) , SMM_CPU_OFFSET (x64._RSP) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42
{4, 8, SMM_CPU_OFFSET (x86._EBP) , SMM_CPU_OFFSET (x64._RBP) , SMM_CPU_OFFSET (x64._RBP) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43
{4, 8, SMM_CPU_OFFSET (x86._ESI) , SMM_CPU_OFFSET (x64._RSI) , SMM_CPU_OFFSET (x64._RSI) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44
{4, 8, SMM_CPU_OFFSET (x86._EDI) , SMM_CPU_OFFSET (x64._RDI) , SMM_CPU_OFFSET (x64._RDI) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45
{4, 8, SMM_CPU_OFFSET (x86._EIP) , SMM_CPU_OFFSET (x64._RIP) , SMM_CPU_OFFSET (x64._RIP) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46
{4, 8, SMM_CPU_OFFSET (x86._EFLAGS) , SMM_CPU_OFFSET (x64._RFLAGS) , SMM_CPU_OFFSET (x64._RFLAGS) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51
{4, 8, SMM_CPU_OFFSET (x86._CR0) , SMM_CPU_OFFSET (x64._CR0) , SMM_CPU_OFFSET (x64._CR0) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52
{4, 8, SMM_CPU_OFFSET (x86._CR3) , SMM_CPU_OFFSET (x64._CR3) , SMM_CPU_OFFSET (x64._CR3) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53
{0, 4, 0 , SMM_CPU_OFFSET (x64._CR4) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54
};
///
/// Lookup table for the IOMisc width information
///
CONST CPU_SMM_SAVE_STATE_IO_WIDTH mSmmCpuIoWidth[] = {
{ 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 0
{ 1, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // SMM_IO_LENGTH_BYTE = 1
{ 2, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT16 }, // SMM_IO_LENGTH_WORD = 2
{ 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 3
{ 4, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32 }, // SMM_IO_LENGTH_DWORD = 4
{ 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 5
{ 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 6
{ 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 } // Undefined = 7
};
///
/// Lookup table for the IOMisc type information
///
CONST EFI_SMM_SAVE_STATE_IO_TYPE mSmmCpuIoType[] = {
EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT, // SMM_IO_TYPE_OUT_DX = 0
EFI_SMM_SAVE_STATE_IO_TYPE_INPUT, // SMM_IO_TYPE_IN_DX = 1
EFI_SMM_SAVE_STATE_IO_TYPE_STRING, // SMM_IO_TYPE_OUTS = 2
EFI_SMM_SAVE_STATE_IO_TYPE_STRING, // SMM_IO_TYPE_INS = 3
(EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 4
(EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 5
EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_OUTS = 6
EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_INS = 7
EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT, // SMM_IO_TYPE_OUT_IMMEDIATE = 8
EFI_SMM_SAVE_STATE_IO_TYPE_INPUT, // SMM_IO_TYPE_OUT_IMMEDIATE = 9
(EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 10
(EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 11
(EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 12
(EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 13
(EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 14
(EFI_SMM_SAVE_STATE_IO_TYPE)0 // Undefined = 15
};
///
/// The mode of the CPU at the time an SMI occurs
///
UINT8 mSmmSaveStateRegisterLma;
/**
Read information from the CPU save state.
@param Register Specifies the CPU register to read form the save state.
@retval 0 Register is not valid
@retval >0 Index into mSmmCpuWidthOffset[] associated with Register
**/
UINTN
GetRegisterIndex (
IN EFI_SMM_SAVE_STATE_REGISTER Register
)
{
UINTN Index;
UINTN Offset;
for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_MAX_INDEX; mSmmCpuRegisterRanges[Index].Length != 0; Index++) {
if (Register >= mSmmCpuRegisterRanges[Index].Start && Register <= mSmmCpuRegisterRanges[Index].End) {
return Register - mSmmCpuRegisterRanges[Index].Start + Offset;
}
Offset += mSmmCpuRegisterRanges[Index].Length;
}
return 0;
}
/**
Read a CPU Save State register on the target processor.
This function abstracts the differences that whether the CPU Save State register is in the
IA32 CPU Save State Map or X64 CPU Save State Map.
This function supports reading a CPU Save State register in SMBase relocation handler.
@param[in] CpuIndex Specifies the zero-based index of the CPU save state.
@param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
@param[in] Width The number of bytes to read from the CPU save state.
@param[out] Buffer Upon return, this holds the CPU register value read from the save state.
@retval EFI_SUCCESS The register was read from Save State.
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
@retval EFI_INVALID_PARAMTER This or Buffer is NULL.
**/
EFI_STATUS
ReadSaveStateRegisterByIndex (
IN UINTN CpuIndex,
IN UINTN RegisterIndex,
IN UINTN Width,
OUT VOID *Buffer
)
{
SMRAM_SAVE_STATE_MAP *CpuSaveState;
if (RegisterIndex == 0) {
return EFI_NOT_FOUND;
}
CpuSaveState = gSmst->CpuSaveState[CpuIndex];
if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
//
// If 32-bit mode width is zero, then the specified register can not be accessed
//
if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {
return EFI_NOT_FOUND;
}
//
// If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
//
if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {
return EFI_INVALID_PARAMETER;
}
//
// Write return buffer
//
ASSERT(CpuSaveState != NULL);
CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Width);
} else {
//
// If 64-bit mode width is zero, then the specified register can not be accessed
//
if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {
return EFI_NOT_FOUND;
}
//
// If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
//
if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {
return EFI_INVALID_PARAMETER;
}
//
// Write lower 32-bits of return buffer
//
CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, MIN(4, Width));
if (Width >= 4) {
//
// Write upper 32-bits of return buffer
//
CopyMem((UINT8 *)Buffer + 4, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, Width - 4);
}
}
return EFI_SUCCESS;
}
/**
Read a CPU Save State register on the target processor.
This function abstracts the differences that whether the CPU Save State register is in the
IA32 CPU Save State Map or X64 CPU Save State Map.
This function supports reading a CPU Save State register in SMBase relocation handler.
@param[in] CpuIndex Specifies the zero-based index of the CPU save state.
@param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
@param[in] Width The number of bytes to read from the CPU save state.
@param[out] Buffer Upon return, this holds the CPU register value read from the save state.
@retval EFI_SUCCESS The register was read from Save State.
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
@retval EFI_INVALID_PARAMTER This or Buffer is NULL.
**/
EFI_STATUS
EFIAPI
ReadSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
OUT VOID *Buffer
)
{
UINT32 SmmRevId;
SMRAM_SAVE_STATE_IOMISC IoMisc;
EFI_SMM_SAVE_STATE_IO_INFO *IoInfo;
VOID *IoMemAddr;
//
// Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
//
if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
//
// Only byte access is supported for this register
//
if (Width != 1) {
return EFI_INVALID_PARAMETER;
}
*(UINT8 *)Buffer = mSmmSaveStateRegisterLma;
return EFI_SUCCESS;
}
//
// Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
//
if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
//
// Get SMM Revision ID
//
ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof(SmmRevId), &SmmRevId);
//
// See if the CPU supports the IOMisc register in the save state
//
if (SmmRevId < SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC) {
return EFI_NOT_FOUND;
}
//
// Get the IOMisc register value
//
ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX, sizeof(IoMisc.Uint32), &IoMisc.Uint32);
//
// Check for the SMI_FLAG in IOMisc
//
if (IoMisc.Bits.SmiFlag == 0) {
return EFI_NOT_FOUND;
}
//
// Compute index for the I/O Length and I/O Type lookup tables
//
if (mSmmCpuIoWidth[IoMisc.Bits.Length].Width == 0 || mSmmCpuIoType[IoMisc.Bits.Type] == 0) {
return EFI_NOT_FOUND;
}
//
// Zero the IoInfo structure that will be returned in Buffer
//
IoInfo = (EFI_SMM_SAVE_STATE_IO_INFO *)Buffer;
ZeroMem (IoInfo, sizeof(EFI_SMM_SAVE_STATE_IO_INFO));
//
// Use lookup tables to help fill in all the fields of the IoInfo structure
//
IoInfo->IoPort = (UINT16)IoMisc.Bits.Port;
IoInfo->IoWidth = mSmmCpuIoWidth[IoMisc.Bits.Length].IoWidth;
IoInfo->IoType = mSmmCpuIoType[IoMisc.Bits.Type];
if (IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_INPUT || IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) {
ReadSaveStateRegister (CpuIndex, EFI_SMM_SAVE_STATE_REGISTER_RAX, mSmmCpuIoWidth[IoMisc.Bits.Length].Width, &IoInfo->IoData);
}
else {
ReadSaveStateRegisterByIndex(CpuIndex, SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX, sizeof(IoMemAddr), &IoMemAddr);
CopyMem(&IoInfo->IoData, IoMemAddr, mSmmCpuIoWidth[IoMisc.Bits.Length].Width);
}
return EFI_SUCCESS;
}
//
// Convert Register to a register lookup table index
//
return ReadSaveStateRegisterByIndex (CpuIndex, GetRegisterIndex (Register), Width, Buffer);
}
/**
Write value to a CPU Save State register on the target processor.
This function abstracts the differences that whether the CPU Save State register is in the
IA32 CPU Save State Map or X64 CPU Save State Map.
This function supports writing a CPU Save State register in SMBase relocation handler.
@param[in] CpuIndex Specifies the zero-based index of the CPU save state.
@param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
@param[in] Width The number of bytes to read from the CPU save state.
@param[in] Buffer Upon entry, this holds the new CPU register value.
@retval EFI_SUCCESS The register was written to Save State.
@retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
@retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct.
**/
EFI_STATUS
EFIAPI
WriteSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
IN CONST VOID *Buffer
)
{
UINTN RegisterIndex;
SMRAM_SAVE_STATE_MAP *CpuSaveState;
//
// Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
//
if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
return EFI_SUCCESS;
}
//
// Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
//
if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
return EFI_NOT_FOUND;
}
//
// Convert Register to a register lookup table index
//
RegisterIndex = GetRegisterIndex (Register);
if (RegisterIndex == 0) {
return EFI_NOT_FOUND;
}
CpuSaveState = gSmst->CpuSaveState[CpuIndex];
//
// Do not write non-writable SaveState, because it will cause exception.
//
if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) {
return EFI_UNSUPPORTED;
}
//
// Check CPU mode
//
if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
//
// If 32-bit mode width is zero, then the specified register can not be accessed
//
if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {
return EFI_NOT_FOUND;
}
//
// If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
//
if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {
return EFI_INVALID_PARAMETER;
}
//
// Write SMM State register
//
ASSERT (CpuSaveState != NULL);
CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Buffer, Width);
} else {
//
// If 64-bit mode width is zero, then the specified register can not be accessed
//
if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {
return EFI_NOT_FOUND;
}
//
// If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
//
if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {
return EFI_INVALID_PARAMETER;
}
//
// Write lower 32-bits of SMM State register
//
CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, Buffer, MIN (4, Width));
if (Width >= 4) {
//
// Write upper 32-bits of SMM State register
//
CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, (UINT8 *)Buffer + 4, Width - 4);
}
}
return EFI_SUCCESS;
}
/**
Hook the code executed immediately after an RSM instruction on the currently
executing CPU. The mode of code executed immediately after RSM must be
detected, and the appropriate hook must be selected. Always clear the auto
HALT restart flag if it is set.
@param[in] CpuIndex The processor index for the currently
executing CPU.
@param[in] CpuState Pointer to SMRAM Save State Map for the
currently executing CPU.
@param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
32-bit mode from 64-bit SMM.
@param[in] NewInstructionPointer Instruction pointer to use if resuming to
same mode as SMM.
@retval The value of the original instruction pointer before it was hooked.
**/
UINT64
EFIAPI
HookReturnFromSmm (
IN UINTN CpuIndex,
SMRAM_SAVE_STATE_MAP *CpuState,
UINT64 NewInstructionPointer32,
UINT64 NewInstructionPointer
)
{
UINT64 OriginalInstructionPointer;
OriginalInstructionPointer = SmmCpuFeaturesHookReturnFromSmm (
CpuIndex,
CpuState,
NewInstructionPointer32,
NewInstructionPointer
);
if (OriginalInstructionPointer != 0) {
return OriginalInstructionPointer;
}
if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
OriginalInstructionPointer = (UINT64)CpuState->x86._EIP;
CpuState->x86._EIP = (UINT32)NewInstructionPointer;
//
// Clear the auto HALT restart flag so the RSM instruction returns
// program control to the instruction following the HLT instruction.
//
if ((CpuState->x86.AutoHALTRestart & BIT0) != 0) {
CpuState->x86.AutoHALTRestart &= ~BIT0;
}
} else {
OriginalInstructionPointer = CpuState->x64._RIP;
if ((CpuState->x64.IA32_EFER & LMA) == 0) {
CpuState->x64._RIP = (UINT32)NewInstructionPointer32;
} else {
CpuState->x64._RIP = (UINT32)NewInstructionPointer;
}
//
// Clear the auto HALT restart flag so the RSM instruction returns
// program control to the instruction following the HLT instruction.
//
if ((CpuState->x64.AutoHALTRestart & BIT0) != 0) {
CpuState->x64.AutoHALTRestart &= ~BIT0;
}
}
return OriginalInstructionPointer;
}
/**
Get the size of the SMI Handler in bytes.
@retval The size, in bytes, of the SMI Handler.
**/
UINTN
EFIAPI
GetSmiHandlerSize (
VOID
)
{
UINTN Size;
Size = SmmCpuFeaturesGetSmiHandlerSize ();
if (Size != 0) {
return Size;
}
return gcSmiHandlerSize;
}
/**
Get the offset of the native SMI Handler.
@retval The offset of the native SMI Handler.
**/
UINTN
EFIAPI
GetSmiHandlerOffset (
VOID
)
{
UINTN Offset;
Offset = SmmCpuFeaturesGetSmiHandlerOffset ();
if (Offset != 0) {
return Offset;
}
return gcSmiHandlerOffset;
}
/**
Install the SMI handler for the CPU specified by CpuIndex. This function
is called by the CPU that was elected as monarch during System Management
Mode initialization.
@param[in] CpuIndex The index of the CPU to install the custom SMI handler.
The value must be between 0 and the NumberOfCpus field
in the System Management System Table (SMST).
@param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
@param[in] SmiStack The stack to use when an SMI is processed by the
the CPU specified by CpuIndex.
@param[in] StackSize The size, in bytes, if the stack used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtBase The base address of the GDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtBase The base address of the IDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] Cr3 The base address of the page tables to use when an SMI
is processed by the CPU specified by CpuIndex.
**/
VOID
EFIAPI
InstallSmiHandler (
IN UINTN CpuIndex,
IN UINT32 SmBase,
IN VOID *SmiStack,
IN UINTN StackSize,
IN UINTN GdtBase,
IN UINTN GdtSize,
IN UINTN IdtBase,
IN UINTN IdtSize,
IN UINT32 Cr3
)
{
if (SmmCpuFeaturesGetSmiHandlerSize () != 0) {
//
// Install SMI handler provided by library
//
SmmCpuFeaturesInstallSmiHandler (
CpuIndex,
SmBase,
SmiStack,
StackSize,
GdtBase,
GdtSize,
IdtBase,
IdtSize,
Cr3
);
return;
}
//
// Initialize values in template before copy
//
gSmiStack = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));
gSmiCr3 = Cr3;
gSmbase = SmBase;
gSmiHandlerIdtr.Base = IdtBase;
gSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);
//
// Set the value at the top of the CPU stack to the CPU Index
//
*(UINTN*)(UINTN)gSmiStack = CpuIndex;
//
// Copy template to CPU specific SMI handler location
//
CopyMem (
(VOID*)(UINTN)(SmBase + SMM_HANDLER_OFFSET),
(VOID*)gcSmiHandlerTemplate,
gcSmiHandlerSize
);
}

View File

@ -0,0 +1,116 @@
/** @file
SMM Timer feature support
Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
UINT64 mTimeoutTicker = 0;
//
// Number of counts in a roll-over cycle of the performance counter.
//
UINT64 mCycle = 0;
//
// Flag to indicate the performance counter is count-up or count-down.
//
BOOLEAN mCountDown;
/**
Initialize Timer for SMM AP Sync.
**/
VOID
InitializeSmmTimer (
VOID
)
{
UINT64 TimerFrequency;
UINT64 Start;
UINT64 End;
TimerFrequency = GetPerformanceCounterProperties (&Start, &End);
mTimeoutTicker = DivU64x32 (
MultU64x64(TimerFrequency, PcdGet64 (PcdCpuSmmApSyncTimeout)),
1000 * 1000
);
if (End < Start) {
mCountDown = TRUE;
mCycle = Start - End;
} else {
mCountDown = FALSE;
mCycle = End - Start;
}
}
/**
Start Timer for SMM AP Sync.
**/
UINT64
EFIAPI
StartSyncTimer (
VOID
)
{
return GetPerformanceCounter ();
}
/**
Check if the SMM AP Sync timer is timeout.
@param Timer The start timer from the begin.
**/
BOOLEAN
EFIAPI
IsSyncTimerTimeout (
IN UINT64 Timer
)
{
UINT64 CurrentTimer;
UINT64 Delta;
CurrentTimer = GetPerformanceCounter ();
//
// We need to consider the case that CurrentTimer is equal to Timer
// when some timer runs too slow and CPU runs fast. We think roll over
// condition does not happen on this case.
//
if (mCountDown) {
//
// The performance counter counts down. Check for roll over condition.
//
if (CurrentTimer <= Timer) {
Delta = Timer - CurrentTimer;
} else {
//
// Handle one roll-over.
//
Delta = mCycle - (CurrentTimer - Timer) + 1;
}
} else {
//
// The performance counter counts up. Check for roll over condition.
//
if (CurrentTimer >= Timer) {
Delta = CurrentTimer - Timer;
} else {
//
// Handle one roll-over.
//
Delta = mCycle - (Timer - CurrentTimer) + 1;
}
}
return (BOOLEAN) (Delta >= mTimeoutTicker);
}

View File

@ -0,0 +1,204 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# MpFuncs.S
#
# Abstract:
#
# This is the assembly code for Multi-processor S3 support
#
#------------------------------------------------------------------------------
.equ VacantFlag, 0x0
.equ NotVacantFlag, 0xff
.equ LockLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart
.equ StackStartAddressLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x08
.equ StackSizeLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x10
.equ CProcedureLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x18
.equ GdtrLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x20
.equ IdtrLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x2A
.equ BufferStartLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x34
.equ Cr3OffsetLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x38
#-------------------------------------------------------------------------------------
#RendezvousFunnelProc procedure follows. All APs execute their procedure. This
#procedure serializes all the AP processors through an Init sequence. It must be
#noted that APs arrive here very raw...ie: real mode, no stack.
#ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
#IS IN MACHINE CODE.
#-------------------------------------------------------------------------------------
#RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
.code:
ASM_GLOBAL ASM_PFX(RendezvousFunnelProc)
ASM_PFX(RendezvousFunnelProc):
RendezvousFunnelProcStart:
# At this point CS = 0x(vv00) and ip= 0x0.
.byte 0x8c,0xc8 # mov ax, cs
.byte 0x8e,0xd8 # mov ds, ax
.byte 0x8e,0xc0 # mov es, ax
.byte 0x8e,0xd0 # mov ss, ax
.byte 0x33,0xc0 # xor ax, ax
.byte 0x8e,0xe0 # mov fs, ax
.byte 0x8e,0xe8 # mov gs, ax
flat32Start:
.byte 0xBE
.word BufferStartLocation
.byte 0x66,0x8B,0x14 # mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer
.byte 0xBE
.word Cr3OffsetLocation
.byte 0x66,0x8B,0xC # mov ecx,dword ptr [si] ; ECX is keeping the value of CR3
.byte 0xBE
.word GdtrLocation
.byte 0x66 # db 66h
.byte 0x2E,0xF,0x1,0x14 # lgdt fword ptr cs:[si]
.byte 0xBE
.word IdtrLocation
.byte 0x66 # db 66h
.byte 0x2E,0xF,0x1,0x1C # lidt fword ptr cs:[si]
.byte 0x33,0xC0 # xor ax, ax
.byte 0x8E,0xD8 # mov ds, ax
.byte 0xF,0x20,0xC0 # mov eax, cr0 ; Get control register 0
.byte 0x66,0x83,0xC8,0x1 # or eax, 000000001h ; Set PE bit (bit #0)
.byte 0xF,0x22,0xC0 # mov cr0, eax
FLAT32_JUMP:
.byte 0x66,0x67,0xEA # far jump
.long 0x0 # 32-bit offset
.word 0x20 # 16-bit selector
PMODE_ENTRY: # protected mode entry point
.byte 0x66,0xB8,0x18,0x0 # mov ax, 18h
.byte 0x66,0x8E,0xD8 # mov ds, ax
.byte 0x66,0x8E,0xC0 # mov es, ax
.byte 0x66,0x8E,0xE0 # mov fs, ax
.byte 0x66,0x8E,0xE8 # mov gs, ax
.byte 0x66,0x8E,0xD0 # mov ss, ax ; Flat mode setup.
.byte 0xF,0x20,0xE0 # mov eax, cr4
.byte 0xF,0xBA,0xE8,0x5 # bts eax, 5
.byte 0xF,0x22,0xE0 # mov cr4, eax
.byte 0xF,0x22,0xD9 # mov cr3, ecx
.byte 0x8B,0xF2 # mov esi, edx ; Save wakeup buffer address
.byte 0xB9
.long 0xC0000080 # mov ecx, 0c0000080h ; EFER MSR number.
.byte 0xF,0x32 # rdmsr ; Read EFER.
.byte 0xF,0xBA,0xE8,0x8 # bts eax, 8 ; Set LME=1.
.byte 0xF,0x30 # wrmsr ; Write EFER.
.byte 0xF,0x20,0xC0 # mov eax, cr0 ; Read CR0.
.byte 0xF,0xBA,0xE8,0x1F # bts eax, 31 ; Set PG=1.
.byte 0xF,0x22,0xC0 # mov cr0, eax ; Write CR0.
LONG_JUMP:
.byte 0x67,0xEA # far jump
.long 0x0 # 32-bit offset
.word 0x38 # 16-bit selector
LongModeStart:
movw $0x30,%ax
.byte 0x66
movw %ax,%ds
.byte 0x66
movw %ax,%es
.byte 0x66
movw %ax,%ss
movl %esi,%edi
addl $LockLocation, %edi
movb $NotVacantFlag, %al
TestLock:
xchgb (%edi), %al
cmpb $NotVacantFlag, %al
jz TestLock
ProgramStack:
movl %esi,%edi
addl $StackSizeLocation, %edi
movq (%edi), %rax
movl %esi,%edi
addl $StackStartAddressLocation, %edi
addq (%edi), %rax
movq %rax, %rsp
movq %rax, (%edi)
Releaselock:
movb $VacantFlag, %al
movl %esi,%edi
addl $LockLocation, %edi
xchgb (%edi), %al
#
# Call assembly function to initialize FPU.
#
movabsq $ASM_PFX(InitializeFloatingPointUnits), %rax
subq $0x20, %rsp
call *%rax
addq $0x20, %rsp
#
# Call C Function
#
movl %esi,%edi
addl $CProcedureLocation, %edi
movq (%edi), %rax
testq %rax, %rax
jz GoToSleep
subq $0x20, %rsp
call *%rax
addq $0x20, %rsp
GoToSleep:
cli
hlt
jmp .-2
RendezvousFunnelProcEnd:
#-------------------------------------------------------------------------------------
# AsmGetAddressMap (&AddressMap);
#-------------------------------------------------------------------------------------
# comments here for definition of address map
ASM_GLOBAL ASM_PFX(AsmGetAddressMap)
ASM_PFX(AsmGetAddressMap):
movabsq $RendezvousFunnelProcStart, %rax
movq %rax, (%rcx)
movq $(PMODE_ENTRY - RendezvousFunnelProcStart), 0x08(%rcx)
movq $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x10(%rcx)
movq $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0x18(%rcx)
movq $(LongModeStart - RendezvousFunnelProcStart), 0x20(%rcx)
movq $(LONG_JUMP - RendezvousFunnelProcStart), 0x28(%rcx)
ret

View File

@ -0,0 +1,206 @@
;------------------------------------------------------------------------------ ;
; Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
; MpFuncs.asm
;
; Abstract:
;
; This is the assembly code for Multi-processor S3 support
;
;-------------------------------------------------------------------------------
EXTERN InitializeFloatingPointUnits:PROC
VacantFlag Equ 00h
NotVacantFlag Equ 0ffh
LockLocation equ RendezvousFunnelProcEnd - RendezvousFunnelProcStart
StackStartAddressLocation equ LockLocation + 08h
StackSizeLocation equ LockLocation + 10h
CProcedureLocation equ LockLocation + 18h
GdtrLocation equ LockLocation + 20h
IdtrLocation equ LockLocation + 2Ah
BufferStartLocation equ LockLocation + 34h
Cr3OffsetLocation equ LockLocation + 38h
;-------------------------------------------------------------------------------------
;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
;procedure serializes all the AP processors through an Init sequence. It must be
;noted that APs arrive here very raw...ie: real mode, no stack.
;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
;IS IN MACHINE CODE.
;-------------------------------------------------------------------------------------
;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
;text SEGMENT
.code
RendezvousFunnelProc PROC
RendezvousFunnelProcStart::
; At this point CS = 0x(vv00) and ip= 0x0.
db 8ch, 0c8h ; mov ax, cs
db 8eh, 0d8h ; mov ds, ax
db 8eh, 0c0h ; mov es, ax
db 8eh, 0d0h ; mov ss, ax
db 33h, 0c0h ; xor ax, ax
db 8eh, 0e0h ; mov fs, ax
db 8eh, 0e8h ; mov gs, ax
flat32Start::
db 0BEh
dw BufferStartLocation ; mov si, BufferStartLocation
db 66h, 8Bh, 14h ; mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer
db 0BEh
dw Cr3OffsetLocation ; mov si, Cr3Location
db 66h, 8Bh, 0Ch ; mov ecx,dword ptr [si] ; ECX is keeping the value of CR3
db 0BEh
dw GdtrLocation ; mov si, GdtrProfile
db 66h ; db 66h
db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
db 0BEh
dw IdtrLocation ; mov si, IdtrProfile
db 66h ; db 66h
db 2Eh, 0Fh, 01h, 1Ch ; lidt fword ptr cs:[si]
db 33h, 0C0h ; xor ax, ax
db 8Eh, 0D8h ; mov ds, ax
db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Get control register 0
db 66h, 83h, 0C8h, 01h ; or eax, 000000001h ; Set PE bit (bit #0)
db 0Fh, 22h, 0C0h ; mov cr0, eax
FLAT32_JUMP::
db 66h, 67h, 0EAh ; far jump
dd 0h ; 32-bit offset
dw 20h ; 16-bit selector
PMODE_ENTRY:: ; protected mode entry point
db 66h, 0B8h, 18h, 00h ; mov ax, 18h
db 66h, 8Eh, 0D8h ; mov ds, ax
db 66h, 8Eh, 0C0h ; mov es, ax
db 66h, 8Eh, 0E0h ; mov fs, ax
db 66h, 8Eh, 0E8h ; mov gs, ax
db 66h, 8Eh, 0D0h ; mov ss, ax ; Flat mode setup.
db 0Fh, 20h, 0E0h ; mov eax, cr4
db 0Fh, 0BAh, 0E8h, 05h ; bts eax, 5
db 0Fh, 22h, 0E0h ; mov cr4, eax
db 0Fh, 22h, 0D9h ; mov cr3, ecx
db 8Bh, 0F2h ; mov esi, edx ; Save wakeup buffer address
db 0B9h
dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number.
db 0Fh, 32h ; rdmsr ; Read EFER.
db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1.
db 0Fh, 30h ; wrmsr ; Write EFER.
db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0.
db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1.
db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0.
LONG_JUMP::
db 67h, 0EAh ; far jump
dd 0h ; 32-bit offset
dw 38h ; 16-bit selector
LongModeStart::
mov ax, 30h
mov ds, ax
mov es, ax
mov ss, ax
mov edi, esi
add edi, LockLocation
mov al, NotVacantFlag
TestLock::
xchg byte ptr [edi], al
cmp al, NotVacantFlag
jz TestLock
ProgramStack::
mov edi, esi
add edi, StackSizeLocation
mov rax, qword ptr [edi]
mov edi, esi
add edi, StackStartAddressLocation
add rax, qword ptr [edi]
mov rsp, rax
mov qword ptr [edi], rax
Releaselock::
mov al, VacantFlag
mov edi, esi
add edi, LockLocation
xchg byte ptr [edi], al
;
; Call assembly function to initialize FPU.
;
mov rax, InitializeFloatingPointUnits
sub rsp, 20h
call rax
add rsp, 20h
;
; Call C Function
;
mov edi, esi
add edi, CProcedureLocation
mov rax, qword ptr [edi]
test rax, rax
jz GoToSleep
sub rsp, 20h
call rax
add rsp, 20h
GoToSleep::
cli
hlt
jmp $-2
RendezvousFunnelProcEnd::
RendezvousFunnelProc ENDP
;-------------------------------------------------------------------------------------
; AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
; comments here for definition of address map
AsmGetAddressMap PROC
mov rax, offset RendezvousFunnelProcStart
mov qword ptr [rcx], rax
mov qword ptr [rcx+8h], PMODE_ENTRY - RendezvousFunnelProcStart
mov qword ptr [rcx+10h], FLAT32_JUMP - RendezvousFunnelProcStart
mov qword ptr [rcx+18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
mov qword ptr [rcx+20h], LongModeStart - RendezvousFunnelProcStart
mov qword ptr [rcx+28h], LONG_JUMP - RendezvousFunnelProcStart
ret
AsmGetAddressMap ENDP
END

View File

@ -0,0 +1,692 @@
/** @file
Page Fault (#PF) handler for X64 processors
Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
#define PAGE_TABLE_PAGES 8
#define ACC_MAX_BIT BIT3
LIST_ENTRY mPagePool = INITIALIZE_LIST_HEAD_VARIABLE (mPagePool);
SPIN_LOCK mPFLock;
BOOLEAN m1GPageTableSupport = FALSE;
/**
Check if 1-GByte pages is supported by processor or not.
@retval TRUE 1-GByte pages is supported.
@retval FALSE 1-GByte pages is not supported.
**/
BOOLEAN
Is1GPageSupport (
VOID
)
{
UINT32 RegEax;
UINT32 RegEdx;
AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
if (RegEax >= 0x80000001) {
AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
if ((RegEdx & BIT26) != 0) {
return TRUE;
}
}
return FALSE;
}
/**
Set sub-entries number in entry.
@param[in, out] Entry Pointer to entry
@param[in] SubEntryNum Sub-entries number based on 0:
0 means there is 1 sub-entry under this entry
0x1ff means there is 512 sub-entries under this entry
**/
VOID
SetSubEntriesNum (
IN OUT UINT64 *Entry,
IN UINT64 SubEntryNum
)
{
//
// Sub-entries number is saved in BIT52 to BIT60 (reserved field) in Entry
//
*Entry = BitFieldWrite64 (*Entry, 52, 60, SubEntryNum);
}
/**
Return sub-entries number in entry.
@param[in] Entry Pointer to entry
@return Sub-entries number based on 0:
0 means there is 1 sub-entry under this entry
0x1ff means there is 512 sub-entries under this entry
**/
UINT64
GetSubEntriesNum (
IN UINT64 *Entry
)
{
//
// Sub-entries number is saved in BIT52 to BIT60 (reserved field) in Entry
//
return BitFieldRead64 (*Entry, 52, 60);
}
/**
Create PageTable for SMM use.
@return The address of PML4 (to set CR3).
**/
UINT32
SmmInitPageTable (
VOID
)
{
EFI_PHYSICAL_ADDRESS Pages;
UINT64 *PTEntry;
LIST_ENTRY *FreePage;
UINTN Index;
UINTN PageFaultHandlerHookAddress;
IA32_IDT_GATE_DESCRIPTOR *IdtEntry;
//
// Initialize spin lock
//
InitializeSpinLock (&mPFLock);
m1GPageTableSupport = Is1GPageSupport ();
//
// Generate PAE page table for the first 4GB memory space
//
Pages = Gen4GPageTable (PAGE_TABLE_PAGES + 1, FALSE);
//
// Set IA32_PG_PMNT bit to mask this entry
//
PTEntry = (UINT64*)(UINTN)Pages;
for (Index = 0; Index < 4; Index++) {
PTEntry[Index] |= IA32_PG_PMNT;
}
//
// Fill Page-Table-Level4 (PML4) entry
//
PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (PAGE_TABLE_PAGES + 1));
*PTEntry = Pages + PAGE_ATTRIBUTE_BITS;
ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));
//
// Set sub-entries number
//
SetSubEntriesNum (PTEntry, 3);
//
// Add remaining pages to page pool
//
FreePage = (LIST_ENTRY*)(PTEntry + EFI_PAGE_SIZE / sizeof (*PTEntry));
while ((UINTN)FreePage < Pages) {
InsertTailList (&mPagePool, FreePage);
FreePage += EFI_PAGE_SIZE / sizeof (*FreePage);
}
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
//
// Set own Page Fault entry instead of the default one, because SMM Profile
// feature depends on IRET instruction to do Single Step
//
PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile;
IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base;
IdtEntry += EXCEPT_IA32_PAGE_FAULT;
IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress;
IdtEntry->Bits.Reserved_0 = 0;
IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16);
IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32);
IdtEntry->Bits.Reserved_1 = 0;
} else {
//
// Register Smm Page Fault Handler
//
SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);
}
//
// Additional SMM IDT initialization for SMM stack guard
//
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
InitializeIDTSmmStackGuard ();
}
//
// Return the address of PML4 (to set CR3)
//
return (UINT32)(UINTN)PTEntry;
}
/**
Set access record in entry.
@param[in, out] Entry Pointer to entry
@param[in] Acc Access record value
**/
VOID
SetAccNum (
IN OUT UINT64 *Entry,
IN UINT64 Acc
)
{
//
// Access record is saved in BIT9 to BIT11 (reserved field) in Entry
//
*Entry = BitFieldWrite64 (*Entry, 9, 11, Acc);
}
/**
Return access record in entry.
@param[in] Entry Pointer to entry
@return Access record value.
**/
UINT64
GetAccNum (
IN UINT64 *Entry
)
{
//
// Access record is saved in BIT9 to BIT11 (reserved field) in Entry
//
return BitFieldRead64 (*Entry, 9, 11);
}
/**
Return and update the access record in entry.
@param[in, out] Entry Pointer to entry
@return Access record value.
**/
UINT64
GetAndUpdateAccNum (
IN OUT UINT64 *Entry
)
{
UINT64 Acc;
Acc = GetAccNum (Entry);
if ((*Entry & IA32_PG_A) != 0) {
//
// If this entry has been accessed, clear access flag in Entry and update access record
// to the initial value 7, adding ACC_MAX_BIT is to make it larger than others
//
*Entry &= ~(UINT64)(UINTN)IA32_PG_A;
SetAccNum (Entry, 0x7);
return (0x7 + ACC_MAX_BIT);
} else {
if (Acc != 0) {
//
// If the access record is not the smallest value 0, minus 1 and update the access record field
//
SetAccNum (Entry, Acc - 1);
}
}
return Acc;
}
/**
Reclaim free pages for PageFault handler.
Search the whole entries tree to find the leaf entry that has the smallest
access record value. Insert the page pointed by this leaf entry into the
page pool. And check its upper entries if need to be inserted into the page
pool or not.
**/
VOID
ReclaimPages (
VOID
)
{
UINT64 *Pml4;
UINT64 *Pdpt;
UINT64 *Pdt;
UINTN Pml4Index;
UINTN PdptIndex;
UINTN PdtIndex;
UINTN MinPml4;
UINTN MinPdpt;
UINTN MinPdt;
UINT64 MinAcc;
UINT64 Acc;
UINT64 SubEntriesNum;
BOOLEAN PML4EIgnore;
BOOLEAN PDPTEIgnore;
UINT64 *ReleasePageAddress;
Pml4 = NULL;
Pdpt = NULL;
Pdt = NULL;
MinAcc = (UINT64)-1;
MinPml4 = (UINTN)-1;
MinPdpt = (UINTN)-1;
MinPdt = (UINTN)-1;
Acc = 0;
ReleasePageAddress = 0;
//
// First, find the leaf entry has the smallest access record value
//
Pml4 = (UINT64*)(UINTN)(AsmReadCr3 () & gPhyMask);
for (Pml4Index = 0; Pml4Index < EFI_PAGE_SIZE / sizeof (*Pml4); Pml4Index++) {
if ((Pml4[Pml4Index] & IA32_PG_P) == 0 || (Pml4[Pml4Index] & IA32_PG_PMNT) != 0) {
//
// If the PML4 entry is not present or is masked, skip it
//
continue;
}
Pdpt = (UINT64*)(UINTN)(Pml4[Pml4Index] & gPhyMask);
PML4EIgnore = FALSE;
for (PdptIndex = 0; PdptIndex < EFI_PAGE_SIZE / sizeof (*Pdpt); PdptIndex++) {
if ((Pdpt[PdptIndex] & IA32_PG_P) == 0 || (Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) {
//
// If the PDPT entry is not present or is masked, skip it
//
if ((Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) {
//
// If the PDPT entry is masked, we will ignore checking the PML4 entry
//
PML4EIgnore = TRUE;
}
continue;
}
if ((Pdpt[PdptIndex] & IA32_PG_PS) == 0) {
//
// It's not 1-GByte pages entry, it should be a PDPT entry,
// we will not check PML4 entry more
//
PML4EIgnore = TRUE;
Pdt = (UINT64*)(UINTN)(Pdpt[PdptIndex] & gPhyMask);
PDPTEIgnore = FALSE;
for (PdtIndex = 0; PdtIndex < EFI_PAGE_SIZE / sizeof(*Pdt); PdtIndex++) {
if ((Pdt[PdtIndex] & IA32_PG_P) == 0 || (Pdt[PdtIndex] & IA32_PG_PMNT) != 0) {
//
// If the PD entry is not present or is masked, skip it
//
if ((Pdt[PdtIndex] & IA32_PG_PMNT) != 0) {
//
// If the PD entry is masked, we will not PDPT entry more
//
PDPTEIgnore = TRUE;
}
continue;
}
if ((Pdt[PdtIndex] & IA32_PG_PS) == 0) {
//
// It's not 2 MByte page table entry, it should be PD entry
// we will find the entry has the smallest access record value
//
PDPTEIgnore = TRUE;
Acc = GetAndUpdateAccNum (Pdt + PdtIndex);
if (Acc < MinAcc) {
//
// If the PD entry has the smallest access record value,
// save the Page address to be released
//
MinAcc = Acc;
MinPml4 = Pml4Index;
MinPdpt = PdptIndex;
MinPdt = PdtIndex;
ReleasePageAddress = Pdt + PdtIndex;
}
}
}
if (!PDPTEIgnore) {
//
// If this PDPT entry has no PDT entries pointer to 4 KByte pages,
// it should only has the entries point to 2 MByte Pages
//
Acc = GetAndUpdateAccNum (Pdpt + PdptIndex);
if (Acc < MinAcc) {
//
// If the PDPT entry has the smallest access record value,
// save the Page address to be released
//
MinAcc = Acc;
MinPml4 = Pml4Index;
MinPdpt = PdptIndex;
MinPdt = (UINTN)-1;
ReleasePageAddress = Pdpt + PdptIndex;
}
}
}
}
if (!PML4EIgnore) {
//
// If PML4 entry has no the PDPT entry pointer to 2 MByte pages,
// it should only has the entries point to 1 GByte Pages
//
Acc = GetAndUpdateAccNum (Pml4 + Pml4Index);
if (Acc < MinAcc) {
//
// If the PML4 entry has the smallest access record value,
// save the Page address to be released
//
MinAcc = Acc;
MinPml4 = Pml4Index;
MinPdpt = (UINTN)-1;
MinPdt = (UINTN)-1;
ReleasePageAddress = Pml4 + Pml4Index;
}
}
}
//
// Make sure one PML4/PDPT/PD entry is selected
//
ASSERT (MinAcc != (UINT64)-1);
//
// Secondly, insert the page pointed by this entry into page pool and clear this entry
//
InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(*ReleasePageAddress & gPhyMask));
*ReleasePageAddress = 0;
//
// Lastly, check this entry's upper entries if need to be inserted into page pool
// or not
//
while (TRUE) {
if (MinPdt != (UINTN)-1) {
//
// If 4 KByte Page Table is released, check the PDPT entry
//
Pdpt = (UINT64*)(UINTN)(Pml4[MinPml4] & gPhyMask);
SubEntriesNum = GetSubEntriesNum(Pdpt + MinPdpt);
if (SubEntriesNum == 0) {
//
// Release the empty Page Directory table if there was no more 4 KByte Page Table entry
// clear the Page directory entry
//
InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(Pdpt[MinPdpt] & gPhyMask));
Pdpt[MinPdpt] = 0;
//
// Go on checking the PML4 table
//
MinPdt = (UINTN)-1;
continue;
}
//
// Update the sub-entries filed in PDPT entry and exit
//
SetSubEntriesNum (Pdpt + MinPdpt, SubEntriesNum - 1);
break;
}
if (MinPdpt != (UINTN)-1) {
//
// One 2MB Page Table is released or Page Directory table is released, check the PML4 entry
//
SubEntriesNum = GetSubEntriesNum (Pml4 + MinPml4);
if (SubEntriesNum == 0) {
//
// Release the empty PML4 table if there was no more 1G KByte Page Table entry
// clear the Page directory entry
//
InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(Pml4[MinPml4] & gPhyMask));
Pml4[MinPml4] = 0;
MinPdpt = (UINTN)-1;
continue;
}
//
// Update the sub-entries filed in PML4 entry and exit
//
SetSubEntriesNum (Pml4 + MinPml4, SubEntriesNum - 1);
break;
}
//
// PLM4 table has been released before, exit it
//
break;
}
}
/**
Allocate free Page for PageFault handler use.
@return Page address.
**/
UINT64
AllocPage (
VOID
)
{
UINT64 RetVal;
if (IsListEmpty (&mPagePool)) {
//
// If page pool is empty, reclaim the used pages and insert one into page pool
//
ReclaimPages ();
}
//
// Get one free page and remove it from page pool
//
RetVal = (UINT64)(UINTN)mPagePool.ForwardLink;
RemoveEntryList (mPagePool.ForwardLink);
//
// Clean this page and return
//
ZeroMem ((VOID*)(UINTN)RetVal, EFI_PAGE_SIZE);
return RetVal;
}
/**
Page Fault handler for SMM use.
**/
VOID
SmiDefaultPFHandler (
VOID
)
{
UINT64 *PageTable;
UINT64 *Pml4;
UINT64 PFAddress;
UINTN StartBit;
UINTN EndBit;
UINT64 PTIndex;
UINTN Index;
SMM_PAGE_SIZE_TYPE PageSize;
UINTN NumOfPages;
UINTN PageAttribute;
EFI_STATUS Status;
UINT64 *UpperEntry;
//
// Set default SMM page attribute
//
PageSize = SmmPageSize2M;
NumOfPages = 1;
PageAttribute = 0;
EndBit = 0;
Pml4 = (UINT64*)(AsmReadCr3 () & gPhyMask);
PFAddress = AsmReadCr2 ();
Status = GetPlatformPageTableAttribute (PFAddress, &PageSize, &NumOfPages, &PageAttribute);
//
// If platform not support page table attribute, set default SMM page attribute
//
if (Status != EFI_SUCCESS) {
PageSize = SmmPageSize2M;
NumOfPages = 1;
PageAttribute = 0;
}
if (PageSize >= MaxSmmPageSizeType) {
PageSize = SmmPageSize2M;
}
if (NumOfPages > 512) {
NumOfPages = 512;
}
switch (PageSize) {
case SmmPageSize4K:
//
// BIT12 to BIT20 is Page Table index
//
EndBit = 12;
break;
case SmmPageSize2M:
//
// BIT21 to BIT29 is Page Directory index
//
EndBit = 21;
PageAttribute |= (UINTN)IA32_PG_PS;
break;
case SmmPageSize1G:
if (!m1GPageTableSupport) {
DEBUG ((EFI_D_ERROR, "1-GByte pages is not supported!"));
ASSERT (FALSE);
}
//
// BIT30 to BIT38 is Page Directory Pointer Table index
//
EndBit = 30;
PageAttribute |= (UINTN)IA32_PG_PS;
break;
default:
ASSERT (FALSE);
}
//
// If execute-disable is enabled, set NX bit
//
if (mXdEnabled) {
PageAttribute |= IA32_PG_NX;
}
for (Index = 0; Index < NumOfPages; Index++) {
PageTable = Pml4;
UpperEntry = NULL;
for (StartBit = 39; StartBit > EndBit; StartBit -= 9) {
PTIndex = BitFieldRead64 (PFAddress, StartBit, StartBit + 8);
if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
//
// If the entry is not present, allocate one page from page pool for it
//
PageTable[PTIndex] = AllocPage () | PAGE_ATTRIBUTE_BITS;
} else {
//
// Save the upper entry address
//
UpperEntry = PageTable + PTIndex;
}
//
// BIT9 to BIT11 of entry is used to save access record,
// initialize value is 7
//
PageTable[PTIndex] |= (UINT64)IA32_PG_A;
SetAccNum (PageTable + PTIndex, 7);
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask);
}
PTIndex = BitFieldRead64 (PFAddress, StartBit, StartBit + 8);
if ((PageTable[PTIndex] & IA32_PG_P) != 0) {
//
// Check if the entry has already existed, this issue may occur when the different
// size page entries created under the same entry
//
DEBUG ((EFI_D_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex]));
DEBUG ((EFI_D_ERROR, "New page table overlapped with old page table!\n"));
ASSERT (FALSE);
}
//
// Fill the new entry
//
PageTable[PTIndex] = (PFAddress & gPhyMask & ~((1ull << EndBit) - 1)) |
PageAttribute | IA32_PG_A | PAGE_ATTRIBUTE_BITS;
if (UpperEntry != NULL) {
SetSubEntriesNum (UpperEntry, GetSubEntriesNum (UpperEntry) + 1);
}
//
// Get the next page address if we need to create more page tables
//
PFAddress += (1ull << EndBit);
}
}
/**
ThePage Fault handler wrapper for SMM use.
@param InterruptType Defines the type of interrupt or exception that
occurred on the processor.This parameter is processor architecture specific.
@param SystemContext A pointer to the processor context when
the interrupt occurred on the processor.
**/
VOID
EFIAPI
SmiPFHandler (
IN EFI_EXCEPTION_TYPE InterruptType,
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
UINTN PFAddress;
ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);
AcquireSpinLock (&mPFLock);
PFAddress = AsmReadCr2 ();
//
// If a page fault occurs in SMRAM range, it should be in a SMM stack guard page.
//
if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
(PFAddress >= mCpuHotPlugData.SmrrBase) &&
(PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {
DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));
CpuDeadLoop ();
}
//
// If a page fault occurs in SMM range
//
if ((PFAddress < mCpuHotPlugData.SmrrBase) ||
(PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {
if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) {
DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%lx) out of SMM range after SMM is locked!\n", PFAddress));
DEBUG_CODE (
DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp);
);
CpuDeadLoop ();
}
}
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
SmmProfilePFHandler (
SystemContext.SystemContextX64->Rip,
SystemContext.SystemContextX64->ExceptionData
);
} else {
SmiDefaultPFHandler ();
}
ReleaseSpinLock (&mPFLock);
}

View File

@ -0,0 +1,67 @@
/** @file
Semaphore mechanism to indicate to the BSP that an AP has exited SMM
after SMBASE relocation.
Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
extern UINT32 mSmmRelocationOriginalAddressPtr32;
extern UINT32 mRebasedFlagAddr32;
UINTN mSmmRelocationOriginalAddress;
volatile BOOLEAN *mRebasedFlag;
/**
AP Semaphore operation in 32-bit mode while BSP runs in 64-bit mode.
**/
VOID
SmmRelocationSemaphoreComplete32 (
VOID
);
/**
Hook return address of SMM Save State so that semaphore code
can be executed immediately after AP exits SMM to indicate to
the BSP that an AP has exited SMM after SMBASE relocation.
@param[in] CpuIndex The processor index.
@param[in] RebasedFlag A pointer to a flag that is set to TRUE
immediately after AP exits SMM.
**/
VOID
SemaphoreHook (
IN UINTN CpuIndex,
IN volatile BOOLEAN *RebasedFlag
)
{
SMRAM_SAVE_STATE_MAP *CpuState;
UINTN TempValue;
mRebasedFlag = RebasedFlag;
mRebasedFlagAddr32 = (UINT32)(UINTN)mRebasedFlag;
CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
mSmmRelocationOriginalAddress = HookReturnFromSmm (
CpuIndex,
CpuState,
(UINT64)(UINTN)&SmmRelocationSemaphoreComplete32,
(UINT64)(UINTN)&SmmRelocationSemaphoreComplete
);
//
// Use temp value to fix ICC complier warning
//
TempValue = (UINTN)&mSmmRelocationOriginalAddress;
mSmmRelocationOriginalAddressPtr32 = (UINT32)TempValue;
}

View File

@ -0,0 +1,212 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# SmiEntry.S
#
# Abstract:
#
# Code template of the SMI handler for a particular processor
#
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(gcSmiHandlerTemplate)
ASM_GLOBAL ASM_PFX(gcSmiHandlerSize)
ASM_GLOBAL ASM_PFX(gcSmiHandlerOffset)
ASM_GLOBAL ASM_PFX(gSmiCr3)
ASM_GLOBAL ASM_PFX(gSmiStack)
ASM_GLOBAL ASM_PFX(gSmbase)
ASM_GLOBAL ASM_PFX(gSmiHandlerIdtr)
#
# Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR
#
.equ DSC_OFFSET, 0xfb00
.equ DSC_GDTPTR, 0x48
.equ DSC_GDTSIZ, 0x50
.equ DSC_CS, 0x14
.equ DSC_DS, 0x16
.equ DSC_SS, 0x18
.equ DSC_OTHERSEG, 0x1A
#
# Constants relating to CPU State Save Area
#
.equ SSM_DR6, 0xffd0
.equ SSM_DR7, 0xffc8
.equ PROTECT_MODE_CS, 0x08
.equ PROTECT_MODE_DS, 0x20
.equ LONG_MODE_CS, 0x38
.equ TSS_SEGMENT, 0x40
.equ GDT_SIZE, 0x50
.text
ASM_PFX(gcSmiHandlerOffset): .word _SmiHandler - _SmiEntryPoint + 0x8000
ASM_PFX(gcSmiHandlerTemplate):
_SmiEntryPoint:
#
# The encoding of BX in 16-bit addressing mode is the same as of RDI in 64-
# bit addressing mode. And that coincidence has been used in the following
# "64-bit like" 16-bit code. Be aware that once RDI is referenced as a
# base address register, it is actually BX that is referenced.
#
.byte 0xbb # mov bx, imm16
.word _GdtDesc - _SmiEntryPoint + 0x8000
#
# fix GDT descriptor
#
.byte 0x2e,0xa1 # mov ax, cs:[offset16]
.word DSC_OFFSET + DSC_GDTSIZ
.byte 0x48 # dec ax
.byte 0x2e
movl %eax, (%rdi) # mov cs:[bx], ax
.byte 0x66,0x2e,0xa1 # mov eax, cs:[offset16]
.word DSC_OFFSET + DSC_GDTPTR
.byte 0x2e
movw %ax, 2(%rdi)
.byte 0x66,0x2e
lgdt (%rdi)
#
# Patch ProtectedMode Segment
#
.byte 0xb8
.word PROTECT_MODE_CS
.byte 0x2e
movl %eax, -2(%rdi)
#
# Patch ProtectedMode entry
#
.byte 0x66, 0xbf # mov edi, SMBASE
ASM_PFX(gSmbase): .space 4
lea ((ProtectedMode - _SmiEntryPoint) + 0x8000)(%edi), %ax
.byte 0x2e
movw %ax, -6(%rdi)
#
# Switch into ProtectedMode
#
movq %cr0, %rbx
.byte 0x66
andl $0x9ffafff3, %ebx
.byte 0x66
orl $0x00000023, %ebx
movq %rbx, %cr0
.byte 0x66, 0xea
.space 6
_GdtDesc: .space 6
ProtectedMode:
movw $PROTECT_MODE_DS, %ax
movl %eax, %ds
movl %eax, %es
movl %eax, %fs
movl %eax, %gs
movl %eax, %ss
.byte 0xbc # mov esp, imm32
ASM_PFX(gSmiStack): .space 4
jmp ProtFlatMode
ProtFlatMode:
.byte 0xb8
ASM_PFX(gSmiCr3): .space 4
movq %rax, %cr3
movl $0x668,%eax # as cr4.PGE is not set here, refresh cr3
movq %rax, %cr4 # in PreModifyMtrrs() to flush TLB.
# Load TSS
subl $8, %esp # reserve room in stack
sgdt (%rsp)
movl 2(%rsp), %eax # eax = GDT base
addl $8, %esp
movb $0x89, %dl
movb %dl, (TSS_SEGMENT + 5)(%rax) # clear busy flag
movl $TSS_SEGMENT, %eax
ltr %ax
#
# Switch to LongMode
#
pushq $LONG_MODE_CS # push cs hardcore here
call Base # push return address for retf later
Base:
addl $(LongMode - Base), (%rsp) # offset for far retf, seg is the 1st arg
movl $0xc0000080, %ecx
rdmsr
orb $1,%ah
wrmsr
movq %cr0, %rbx
orl $0x080010000, %ebx # enable paging + WP
movq %rbx, %cr0
retf
LongMode: # long mode (64-bit code) starts here
movabsq $ASM_PFX(gSmiHandlerIdtr), %rax
lidt (%rax)
lea (DSC_OFFSET)(%rdi), %ebx
movw DSC_DS(%rbx), %ax
movl %eax,%ds
movw DSC_OTHERSEG(%rbx), %ax
movl %eax,%es
movl %eax,%fs
movl %eax,%gs
movw DSC_SS(%rbx), %ax
movl %eax,%ss
# jmp _SmiHandler ; instruction is not needed
_SmiHandler:
# below step is needed, because STM does not run above code.
# we have to run below code to set IDT/CR0/CR4
movabsq $ASM_PFX(gSmiHandlerIdtr), %rax
lidt (%rax)
movq %cr0, %rax
orl $0x00000022, %eax
orl $0x00010000, %eax # enable WP
movq %rax, %cr0
movq %cr4, %rax
movl $0x668, %eax # as cr4.PGE is not set here, refresh cr3
movq %rax, %cr4 # in PreModifyMtrrs() to flush TLB.
# STM init finish
movq (%rsp), %rbx
# Save FP registers
subq $0x208, %rsp
.byte 0x48 # FXSAVE64
fxsave (%rsp)
addq $-0x20, %rsp
movq %rbx, %rcx
movabsq $ASM_PFX(CpuSmmDebugEntry), %rax
call *%rax
movq %rbx, %rcx
movabsq $ASM_PFX(SmiRendezvous), %rax
call *%rax
movq %rbx, %rcx
movabsq $ASM_PFX(CpuSmmDebugExit), %rax
call *%rax
addq $0x20, %rsp
#
# Restore FP registers
#
.byte 0x48 # FXRSTOR64
fxrstor (%rsp)
rsm
ASM_PFX(gcSmiHandlerSize): .word . - _SmiEntryPoint

View File

@ -0,0 +1,214 @@
;------------------------------------------------------------------------------ ;
; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
; SmiEntry.asm
;
; Abstract:
;
; Code template of the SMI handler for a particular processor
;
;-------------------------------------------------------------------------------
;
; Variables referenced by C code
;
EXTERNDEF SmiRendezvous:PROC
EXTERNDEF CpuSmmDebugEntry:PROC
EXTERNDEF CpuSmmDebugExit:PROC
EXTERNDEF gcSmiHandlerTemplate:BYTE
EXTERNDEF gcSmiHandlerSize:WORD
EXTERNDEF gcSmiHandlerOffset:WORD
EXTERNDEF gSmiCr3:DWORD
EXTERNDEF gSmiStack:DWORD
EXTERNDEF gSmbase:DWORD
EXTERNDEF gSmiHandlerIdtr:FWORD
;
; Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR
;
DSC_OFFSET EQU 0fb00h
DSC_GDTPTR EQU 48h
DSC_GDTSIZ EQU 50h
DSC_CS EQU 14h
DSC_DS EQU 16h
DSC_SS EQU 18h
DSC_OTHERSEG EQU 1Ah
;
; Constants relating to CPU State Save Area
;
SSM_DR6 EQU 0ffd0h
SSM_DR7 EQU 0ffc8h
PROTECT_MODE_CS EQU 08h
PROTECT_MODE_DS EQU 20h
LONG_MODE_CS EQU 38h
TSS_SEGMENT EQU 40h
GDT_SIZE EQU 50h
.const
gcSmiHandlerOffset DW _SmiHandler - _SmiEntryPoint + 8000h
.code
gcSmiHandlerTemplate LABEL BYTE
_SmiEntryPoint:
;
; The encoding of BX in 16-bit addressing mode is the same as of RDI in 64-
; bit addressing mode. And that coincidence has been used in the following
; "64-bit like" 16-bit code. Be aware that once RDI is referenced as a
; base address register, it is actually BX that is referenced.
;
DB 0bbh ; mov bx, imm16
DW offset _GdtDesc - _SmiEntryPoint + 8000h ; bx = GdtDesc offset
; fix GDT descriptor
DB 2eh, 0a1h ; mov ax, cs:[offset16]
DW DSC_OFFSET + DSC_GDTSIZ
DB 48h ; dec ax
DB 2eh
mov [rdi], eax ; mov cs:[bx], ax
DB 66h, 2eh, 0a1h ; mov eax, cs:[offset16]
DW DSC_OFFSET + DSC_GDTPTR
DB 2eh
mov [rdi + 2], ax ; mov cs:[bx + 2], eax
DB 66h, 2eh
lgdt fword ptr [rdi] ; lgdt fword ptr cs:[bx]
; Patch ProtectedMode Segment
DB 0b8h ; mov ax, imm16
DW PROTECT_MODE_CS ; set AX for segment directly
DB 2eh
mov [rdi - 2], eax ; mov cs:[bx - 2], ax
; Patch ProtectedMode entry
DB 66h, 0bfh ; mov edi, SMBASE
gSmbase DD ?
lea ax, [edi + (@ProtectedMode - _SmiEntryPoint) + 8000h]
DB 2eh
mov [rdi - 6], ax ; mov cs:[bx - 6], eax
; Switch into @ProtectedMode
mov rbx, cr0
DB 66h
and ebx, 9ffafff3h
DB 66h
or ebx, 00000023h
mov cr0, rbx
DB 66h, 0eah
DD ?
DW ?
_GdtDesc FWORD ?
@ProtectedMode:
mov ax, PROTECT_MODE_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
DB 0bch ; mov esp, imm32
gSmiStack DD ?
jmp ProtFlatMode
ProtFlatMode:
DB 0b8h ; mov eax, offset gSmiCr3
gSmiCr3 DD ?
mov cr3, rax
mov eax, 668h ; as cr4.PGE is not set here, refresh cr3
mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
; Load TSS
sub esp, 8 ; reserve room in stack
sgdt fword ptr [rsp]
mov eax, [rsp + 2] ; eax = GDT base
add esp, 8
mov dl, 89h
mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag
mov eax, TSS_SEGMENT
ltr ax
; Switch into @LongMode
push LONG_MODE_CS ; push cs hardcore here
call Base ; push return address for retf later
Base:
add dword ptr [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
mov ecx, 0c0000080h
rdmsr
or ah, 1
wrmsr
mov rbx, cr0
or ebx, 080010000h ; enable paging + WP
mov cr0, rbx
retf
@LongMode: ; long mode (64-bit code) starts here
mov rax, offset gSmiHandlerIdtr
lidt fword ptr [rax]
lea ebx, [rdi + DSC_OFFSET]
mov ax, [rbx + DSC_DS]
mov ds, eax
mov ax, [rbx + DSC_OTHERSEG]
mov es, eax
mov fs, eax
mov gs, eax
mov ax, [rbx + DSC_SS]
mov ss, eax
; jmp _SmiHandler ; instruction is not needed
_SmiHandler:
; below step is needed, because STM does not run above code.
; we have to run below code to set IDT/CR0/CR4
mov rax, offset gSmiHandlerIdtr
lidt fword ptr [rax]
mov rax, cr0
or eax, 00000022h
or eax, 00010000h ; enable WP
mov cr0, rax
mov rax, cr4
mov eax, 668h ; as cr4.PGE is not set here, refresh cr3
mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
; STM init finish
mov rbx, [rsp] ; rbx <- CpuIndex
;
; Save FP registers
;
sub rsp, 208h
DB 48h ; FXSAVE64
fxsave [rsp]
add rsp, -20h
mov rcx, rbx
mov rax, CpuSmmDebugEntry
call rax
mov rcx, rbx
mov rax, SmiRendezvous ; rax <- absolute addr of SmiRedezvous
call rax
mov rcx, rbx
mov rax, CpuSmmDebugExit
call rax
add rsp, 20h
;
; Restore FP registers
;
DB 48h ; FXRSTOR64
fxrstor [rsp]
rsm
gcSmiHandlerSize DW $ - _SmiEntryPoint
END

View File

@ -0,0 +1,659 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# SmiException.S
#
# Abstract:
#
# Exception handlers used in SM mode
#
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(SmiPFHandler)
ASM_GLOBAL ASM_PFX(gSmiMtrrs)
ASM_GLOBAL ASM_PFX(gcSmiIdtr)
ASM_GLOBAL ASM_PFX(gcSmiGdtr)
ASM_GLOBAL ASM_PFX(gcPsd)
ASM_GLOBAL ASM_PFX(SmmStmExceptionHandler)
ASM_GLOBAL ASM_PFX(SmmStmSetup)
ASM_GLOBAL ASM_PFX(SmmStmTeardown)
.data
NullSeg: .quad 0 # reserved by architecture
CodeSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x9b
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
ProtModeCodeSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x9b
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
ProtModeSsSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x93
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
DataSeg32:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x93
.byte 0xcf # LimitHigh
.byte 0 # BaseHigh
CodeSeg16:
.word -1
.word 0
.byte 0
.byte 0x9b
.byte 0x8f
.byte 0
DataSeg16:
.word -1
.word 0
.byte 0
.byte 0x93
.byte 0x8f
.byte 0
CodeSeg64:
.word -1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x9b
.byte 0xaf # LimitHigh
.byte 0 # BaseHigh
# TSS Segment for X64 specially
TssSeg:
.word TSS_DESC_SIZE - 1 # LimitLow
.word 0 # BaseLow
.byte 0 # BaseMid
.byte 0x89
.byte 0x00 # LimitHigh
.byte 0 # BaseHigh
.long 0 # BaseUpper
.long 0 # Reserved
.equ GDT_SIZE, .- NullSeg
TssDescriptor:
.space 104, 0
.equ TSS_DESC_SIZE, .- TssDescriptor
#
# This structure serves as a template for all processors.
#
ASM_PFX(gcPsd):
.ascii "TXTPSSIG"
.word PSD_SIZE
.word 1 # Version
.long 0 # LocalApicId
.byte 0xF # Cr4Pse;Cr4Pae;Intel64Mode;ExecutionDisableOutsideSmrr
.byte 0 # BIOS to STM
.byte 0 # STM to BIOS
.byte 0
.word CODE_SEL
.word DATA_SEL
.word DATA_SEL
.word DATA_SEL
.word TR_SEL
.word 0
.quad 0 # SmmCr3
.quad ASM_PFX(_OnStmSetup)
.quad ASM_PFX(_OnStmTeardown)
.quad 0 # SmmSmiHandlerRip - SMM guest entrypoint
.quad 0 # SmmSmiHandlerRsp
.quad NullSeg
.long GDT_SIZE
.long 0x80010100 # RequiredStmSmmRevId
.quad ASM_PFX(_OnException)
.quad 0 # ExceptionStack
.quad DATA_SEL
.quad 0x1F # ExceptionFilter
.long 0
.quad ASM_PFX(gSmiMtrrs)
.quad 0 # BiosHwResourceRequirementsPtr
.quad 0 # AcpiRsdp
.byte 0 # PhysicalAddressBits
.equ PSD_SIZE, . - ASM_PFX(gcPsd)
#
# CODE & DATA segments for SMM runtime
#
.equ CODE_SEL, CodeSeg64 - NullSeg
.equ DATA_SEL, DataSeg32 - NullSeg
.equ TR_SEL, TssSeg - NullSeg
.equ CODE32_SEL, CodeSeg32 - NullSeg
ASM_PFX(gcSmiGdtr):
.word GDT_SIZE - 1
.quad NullSeg
ASM_PFX(gcSmiIdtr):
.word IDT_SIZE - 1
.quad _SmiIDT
#
# Here is the IDT. There are 32 (not 255) entries in it since only processor
# generated exceptions will be handled.
#
_SmiIDT:
# The following segment repeats 32 times:
# No. 1
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 2
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 3
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 4
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 5
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 6
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 7
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 8
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 9
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 10
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 11
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 12
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 13
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 14
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 15
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 16
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 17
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 18
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 19
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 20
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 21
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 22
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 23
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 24
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 25
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 26
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 27
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 28
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 29
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 30
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 31
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
# No. 32
.word 0 # Offset 0:15
.word CODE_SEL
.byte 0 # Unused
.byte 0x8e # Interrupt Gate, Present
.word 0 # Offset 16:31
.quad 0 # Offset 32:63
_SmiIDTEnd:
.equ IDT_SIZE, (_SmiIDTEnd - _SmiIDT)
.text
#------------------------------------------------------------------------------
# _SmiExceptionEntryPoints is the collection of exception entry points followed
# by a common exception handler.
#
# Stack frame would be as follows as specified in IA32 manuals:
# +---------------------+ <-- 16-byte aligned ensured by processor
# + Old SS +
# +---------------------+
# + Old RSP +
# +---------------------+
# + RFlags +
# +---------------------+
# + CS +
# +---------------------+
# + RIP +
# +---------------------+
# + Error Code +
# +---------------------+
# + Vector Number +
# +---------------------+
# + RBP +
# +---------------------+ <-- RBP, 16-byte aligned
#
# RSP set to odd multiple of 8 at @CommonEntryPoint means ErrCode PRESENT
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(PageFaultIdtHandlerSmmProfile)
ASM_PFX(PageFaultIdtHandlerSmmProfile):
pushq $0x0e # Page Fault
.byte 0x40, 0xf6, 0xc4, 0x08 #test spl, 8
jnz L1
pushq (%rsp)
movq $0, 8(%rsp)
L1:
pushq %rbp
movq %rsp, %rbp
#
# Since here the stack pointer is 16-byte aligned, so
# EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
# is 16-byte aligned
#
## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %r11
pushq %r10
pushq %r9
pushq %r8
pushq %rax
pushq %rcx
pushq %rdx
pushq %rbx
pushq 48(%rbp) # RSP
pushq (%rbp) # RBP
pushq %rsi
pushq %rdi
## UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
movzwq 56(%rbp), %rax
pushq %rax # for ss
movzwq 32(%rbp), %rax
pushq %rax # for cs
movq %ds, %rax
pushq %rax
movq %es, %rax
pushq %rax
movq %fs, %rax
pushq %rax
movq %gs, %rax
pushq %rax
## UINT64 Rip;
pushq 24(%rbp)
## UINT64 Gdtr[2], Idtr[2];
subq $16, %rsp
sidt (%rsp)
subq $16, %rsp
sgdt (%rsp)
## UINT64 Ldtr, Tr;
xorq %rax, %rax
strw %ax
pushq %rax
sldtw %ax
pushq %rax
## UINT64 RFlags;
pushq 40(%rbp)
## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
movq %cr8, %rax
pushq %rax
movq %cr4, %rax
orq $0x208, %rax
movq %rax, %cr4
pushq %rax
movq %cr3, %rax
pushq %rax
movq %cr2, %rax
pushq %rax
xorq %rax, %rax
pushq %rax
movq %cr0, %rax
pushq %rax
## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
movq %dr7, %rax
pushq %rax
movq %dr6, %rax
pushq %rax
movq %dr3, %rax
pushq %rax
movq %dr2, %rax
pushq %rax
movq %dr1, %rax
pushq %rax
movq %dr0, %rax
pushq %rax
## FX_SAVE_STATE_X64 FxSaveState;
subq $512, %rsp
movq %rsp, %rdi
.byte 0xf, 0xae, 0x7 # fxsave [rdi]
# UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
cld
## UINT32 ExceptionData;
pushq 16(%rbp)
## call into exception handler
movq 8(%rbp), %rcx
movabsq $ASM_PFX(SmiPFHandler), %rax
## Prepare parameter and call
movq %rsp, %rdx
#
# Per X64 calling convention, allocate maximum parameter stack space
# and make sure RSP is 16-byte aligned
#
subq $4 * 8 + 8, %rsp
call *%rax
addq $4 * 8 + 8, %rsp
jmp L5
L5:
## UINT64 ExceptionData;
addq $8, %rsp
## FX_SAVE_STATE_X64 FxSaveState;
movq %rsp, %rsi
.byte 0xf, 0xae, 0xe # fxrstor [rsi]
addq $512, %rsp
## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
## Skip restoration of DRx registers to support debuggers
## that set breakpoints in interrupt/exception context
addq $8 * 6, %rsp
## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
popq %rax
movq %rax, %cr0
addq $8, %rsp # not for Cr1
popq %rax
movq %rax, %cr2
popq %rax
movq %rax, %cr3
popq %rax
movq %rax, %cr4
popq %rax
movq %rax, %cr8
## UINT64 RFlags;
popq 40(%rbp)
## UINT64 Ldtr, Tr;
## UINT64 Gdtr[2], Idtr[2];
## Best not let anyone mess with these particular registers...
addq $48, %rsp
## UINT64 Rip;
popq 24(%rbp)
## UINT64 Gs, Fs, Es, Ds, Cs, Ss;
popq %rax
# mov gs, rax ; not for gs
popq %rax
# mov fs, rax ; not for fs
# (X64 will not use fs and gs, so we do not restore it)
popq %rax
movq %rax, %es
popq %rax
movq %rax, %ds
popq 32(%rbp) # for cs
popq 56(%rbp) # for ss
## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
popq %rdi
popq %rsi
addq $8, %rsp # not for rbp
popq 48(%rbp) # for rsp
popq %rbx
popq %rdx
popq %rcx
popq %rax
popq %r8
popq %r9
popq %r10
popq %r11
popq %r12
popq %r13
popq %r14
popq %r15
movq %rbp, %rsp
# Enable TF bit after page fault handler runs
btsl $8, 40(%rsp) #RFLAGS
popq %rbp
addq $16, %rsp # skip INT# & ErrCode
iretq
ASM_GLOBAL ASM_PFX(InitializeIDTSmmStackGuard)
ASM_PFX(InitializeIDTSmmStackGuard):
# If SMM Stack Guard feature is enabled, set the IST field of
# the interrupt gate for Page Fault Exception to be 1
#
movabsq $_SmiIDT + 14 * 16, %rax
movb $1, 4(%rax)
ret
#------------------------------------------------------------------------------
# SMM Exception handlers
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(_OnException)
ASM_PFX(_OnException):
movq %rsp, %rcx
subq $0x28, %rsp
call ASM_PFX(SmmStmExceptionHandler)
addq $0x28, %rsp
movl %eax, %ebx
movl $4, %eax
.byte 0xf, 0x1, 0xc1 # VMCALL
jmp .
ASM_GLOBAL ASM_PFX(_OnStmSetup)
ASM_PFX(_OnStmSetup):
subq $0x28, %rsp
call ASM_PFX(SmmStmSetup)
addq 0x28, %rsp
rsm
ASM_GLOBAL ASM_PFX(_OnStmTeardown)
ASM_PFX(_OnStmTeardown):
subq $0x28, %rsp
call ASM_PFX(SmmStmTeardown)
addq $0x28, %rsp
rsm

View File

@ -0,0 +1,460 @@
;------------------------------------------------------------------------------ ;
; Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
; SmiException.asm
;
; Abstract:
;
; Exception handlers used in SM mode
;
;-------------------------------------------------------------------------------
EXTERNDEF SmiPFHandler:PROC
EXTERNDEF gSmiMtrrs:QWORD
EXTERNDEF gcSmiIdtr:FWORD
EXTERNDEF gcSmiGdtr:FWORD
EXTERNDEF gcPsd:BYTE
SmmStmExceptionHandler PROTO
SmmStmSetup PROTO
SmmStmTeardown PROTO
.const
NullSeg DQ 0 ; reserved by architecture
CodeSeg32 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 9bh
DB 0cfh ; LimitHigh
DB 0 ; BaseHigh
ProtModeCodeSeg32 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 9bh
DB 0cfh ; LimitHigh
DB 0 ; BaseHigh
ProtModeSsSeg32 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 93h
DB 0cfh ; LimitHigh
DB 0 ; BaseHigh
DataSeg32 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 93h
DB 0cfh ; LimitHigh
DB 0 ; BaseHigh
CodeSeg16 LABEL QWORD
DW -1
DW 0
DB 0
DB 9bh
DB 8fh
DB 0
DataSeg16 LABEL QWORD
DW -1
DW 0
DB 0
DB 93h
DB 8fh
DB 0
CodeSeg64 LABEL QWORD
DW -1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 9bh
DB 0afh ; LimitHigh
DB 0 ; BaseHigh
; TSS Segment for X64 specially
TssSeg LABEL QWORD
DW TSS_DESC_SIZE - 1 ; LimitLow
DW 0 ; BaseLow
DB 0 ; BaseMid
DB 89h
DB 00h ; LimitHigh
DB 0 ; BaseHigh
DD 0 ; BaseUpper
DD 0 ; Reserved
GDT_SIZE = $ - offset NullSeg
; Create TSS Descriptor just after GDT
TssDescriptor LABEL BYTE
DD 0 ; Reserved
DQ 0 ; RSP0
DQ 0 ; RSP1
DQ 0 ; RSP2
DD 0 ; Reserved
DD 0 ; Reserved
DQ 0 ; IST1
DQ 0 ; IST2
DQ 0 ; IST3
DQ 0 ; IST4
DQ 0 ; IST5
DQ 0 ; IST6
DQ 0 ; IST7
DD 0 ; Reserved
DD 0 ; Reserved
DW 0 ; Reserved
DW 0 ; I/O Map Base Address
TSS_DESC_SIZE = $ - offset TssDescriptor
;
; This structure serves as a template for all processors.
;
gcPsd LABEL BYTE
DB 'TXTPSSIG'
DW PSD_SIZE
DW 1 ; Version
DD 0 ; LocalApicId
DB 0Fh ; Cr4Pse;Cr4Pae;Intel64Mode;ExecutionDisableOutsideSmrr
DB 0 ; BIOS to STM
DB 0 ; STM to BIOS
DB 0
DW CODE_SEL
DW DATA_SEL
DW DATA_SEL
DW DATA_SEL
DW TR_SEL
DW 0
DQ 0 ; SmmCr3
DQ _OnStmSetup
DQ _OnStmTeardown
DQ 0 ; SmmSmiHandlerRip - SMM guest entrypoint
DQ 0 ; SmmSmiHandlerRsp
DQ offset NullSeg
DD GDT_SIZE
DD 80010100h ; RequiredStmSmmRevId
DQ _OnException
DQ 0 ; ExceptionStack
DW DATA_SEL
DW 01Fh ; ExceptionFilter
DD 0
DQ offset gSmiMtrrs
DQ 0 ; BiosHwResourceRequirementsPtr
DQ 0 ; AcpiRsdp
DB 0 ; PhysicalAddressBits
PSD_SIZE = $ - offset gcPsd
;
; CODE & DATA segments for SMM runtime
;
CODE_SEL = offset CodeSeg64 - offset NullSeg
DATA_SEL = offset DataSeg32 - offset NullSeg
TR_SEL = offset TssSeg - offset NullSeg
CODE32_SEL = offset CodeSeg32 - offset NullSeg
gcSmiGdtr LABEL FWORD
DW GDT_SIZE - 1
DQ offset NullSeg
gcSmiIdtr LABEL FWORD
DW IDT_SIZE - 1
DQ offset _SmiIDT
.data
;
; Here is the IDT. There are 32 (not 255) entries in it since only processor
; generated exceptions will be handled.
;
_SmiIDT:
REPEAT 32
DW 0 ; Offset 0:15
DW CODE_SEL ; Segment selector
DB 0 ; Unused
DB 8eh ; Interrupt Gate, Present
DW 0 ; Offset 16:31
DQ 0 ; Offset 32:63
ENDM
_SmiIDTEnd:
IDT_SIZE = (offset _SmiIDTEnd - offset _SmiIDT)
.code
;------------------------------------------------------------------------------
; _SmiExceptionEntryPoints is the collection of exception entry points followed
; by a common exception handler.
;
; Stack frame would be as follows as specified in IA32 manuals:
;
; +---------------------+ <-- 16-byte aligned ensured by processor
; + Old SS +
; +---------------------+
; + Old RSP +
; +---------------------+
; + RFlags +
; +---------------------+
; + CS +
; +---------------------+
; + RIP +
; +---------------------+
; + Error Code +
; +---------------------+
; + Vector Number +
; +---------------------+
; + RBP +
; +---------------------+ <-- RBP, 16-byte aligned
;
; RSP set to odd multiple of 8 at @CommonEntryPoint means ErrCode PRESENT
;------------------------------------------------------------------------------
PageFaultIdtHandlerSmmProfile PROC
push 0eh ; Page Fault
test spl, 8 ; odd multiple of 8 => ErrCode present
jnz @F
push [rsp] ; duplicate INT# if no ErrCode
mov qword ptr [rsp + 8], 0
@@:
push rbp
mov rbp, rsp
;
; Since here the stack pointer is 16-byte aligned, so
; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
; is 16-byte aligned
;
;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
push r15
push r14
push r13
push r12
push r11
push r10
push r9
push r8
push rax
push rcx
push rdx
push rbx
push qword ptr [rbp + 48] ; RSP
push qword ptr [rbp] ; RBP
push rsi
push rdi
;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
movzx rax, word ptr [rbp + 56]
push rax ; for ss
movzx rax, word ptr [rbp + 32]
push rax ; for cs
mov rax, ds
push rax
mov rax, es
push rax
mov rax, fs
push rax
mov rax, gs
push rax
;; UINT64 Rip;
push qword ptr [rbp + 24]
;; UINT64 Gdtr[2], Idtr[2];
sub rsp, 16
sidt fword ptr [rsp]
sub rsp, 16
sgdt fword ptr [rsp]
;; UINT64 Ldtr, Tr;
xor rax, rax
str ax
push rax
sldt ax
push rax
;; UINT64 RFlags;
push qword ptr [rbp + 40]
;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
mov rax, cr8
push rax
mov rax, cr4
or rax, 208h
mov cr4, rax
push rax
mov rax, cr3
push rax
mov rax, cr2
push rax
xor rax, rax
push rax
mov rax, cr0
push rax
;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
mov rax, dr7
push rax
mov rax, dr6
push rax
mov rax, dr3
push rax
mov rax, dr2
push rax
mov rax, dr1
push rax
mov rax, dr0
push rax
;; FX_SAVE_STATE_X64 FxSaveState;
sub rsp, 512
mov rdi, rsp
db 0fh, 0aeh, 00000111y ;fxsave [rdi]
; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
cld
;; UINT32 ExceptionData;
push qword ptr [rbp + 16]
;; call into exception handler
mov rcx, [rbp + 8]
mov rax, SmiPFHandler
;; Prepare parameter and call
mov rdx, rsp
;
; Per X64 calling convention, allocate maximum parameter stack space
; and make sure RSP is 16-byte aligned
;
sub rsp, 4 * 8 + 8
call rax
add rsp, 4 * 8 + 8
jmp @F
@@:
;; UINT64 ExceptionData;
add rsp, 8
;; FX_SAVE_STATE_X64 FxSaveState;
mov rsi, rsp
db 0fh, 0aeh, 00001110y ; fxrstor [rsi]
add rsp, 512
;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
;; Skip restoration of DRx registers to support debuggers
;; that set breakpoints in interrupt/exception context
add rsp, 8 * 6
;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
pop rax
mov cr0, rax
add rsp, 8 ; not for Cr1
pop rax
mov cr2, rax
pop rax
mov cr3, rax
pop rax
mov cr4, rax
pop rax
mov cr8, rax
;; UINT64 RFlags;
pop qword ptr [rbp + 40]
;; UINT64 Ldtr, Tr;
;; UINT64 Gdtr[2], Idtr[2];
;; Best not let anyone mess with these particular registers...
add rsp, 48
;; UINT64 Rip;
pop qword ptr [rbp + 24]
;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
pop rax
; mov gs, rax ; not for gs
pop rax
; mov fs, rax ; not for fs
; (X64 will not use fs and gs, so we do not restore it)
pop rax
mov es, rax
pop rax
mov ds, rax
pop qword ptr [rbp + 32] ; for cs
pop qword ptr [rbp + 56] ; for ss
;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
pop rdi
pop rsi
add rsp, 8 ; not for rbp
pop qword ptr [rbp + 48] ; for rsp
pop rbx
pop rdx
pop rcx
pop rax
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
mov rsp, rbp
; Enable TF bit after page fault handler runs
bts dword ptr [rsp + 40], 8 ;RFLAGS
pop rbp
add rsp, 16 ; skip INT# & ErrCode
iretq
PageFaultIdtHandlerSmmProfile ENDP
InitializeIDTSmmStackGuard PROC
;
; If SMM Stack Guard feature is enabled, set the IST field of
; the interrupt gate for Page Fault Exception to be 1
;
lea rax, _SmiIDT + 14 * 16
mov byte ptr [rax + 4], 1
ret
InitializeIDTSmmStackGuard ENDP
;------------------------------------------------------------------------------
; SMM Exception handlers
;------------------------------------------------------------------------------
_OnException PROC
mov rcx, rsp
add rsp, -28h
call SmmStmExceptionHandler
add rsp, 28h
mov ebx, eax
mov eax, 4
DB 0fh, 01h, 0c1h ; VMCALL
jmp $
_OnException ENDP
_OnStmSetup PROC
add rsp, -28h
call SmmStmSetup
add rsp, 28h
rsm
_OnStmSetup ENDP
_OnStmTeardown PROC
add rsp, -28h
call SmmStmTeardown
add rsp, 28h
rsm
_OnStmTeardown ENDP
END

View File

@ -0,0 +1,70 @@
/** @file
SMM CPU misc functions for x64 arch specific.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
/**
Initialize Gdt for all processors.
@param[in] Cr3 CR3 value.
@param[out] GdtStepSize The step size for GDT table.
@return GdtBase for processor 0.
GdtBase for processor X is: GdtBase + (GdtStepSize * X)
**/
VOID *
InitGdt (
IN UINTN Cr3,
OUT UINTN *GdtStepSize
)
{
UINTN Index;
IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;
UINTN TssBase;
UINTN GdtTssTableSize;
UINT8 *GdtTssTables;
UINTN GdtTableStepSize;
//
// For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
// on each SMI entry.
//
GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned
GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
ASSERT (GdtTssTables != NULL);
GdtTableStepSize = GdtTssTableSize;
for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);
//
// Fixup TSS descriptors
//
TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
GdtDescriptor->Bits.BaseLow = (UINT16)(UINTN)TssBase;
GdtDescriptor->Bits.BaseMid = (UINT8)((UINTN)TssBase >> 16);
GdtDescriptor->Bits.BaseHigh = (UINT8)((UINTN)TssBase >> 24);
if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
//
// Setup top of known good stack as IST1 for each processor.
//
*(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);
}
}
*GdtStepSize = GdtTableStepSize;
return GdtTssTables;
}

View File

@ -0,0 +1,141 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# SmmInit.S
#
# Abstract:
#
# Functions for relocating SMBASE's for all processors
#
#------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(gSmmCr0)
ASM_GLOBAL ASM_PFX(gSmmCr3)
ASM_GLOBAL ASM_PFX(gSmmCr4)
ASM_GLOBAL ASM_PFX(gSmmJmpAddr)
ASM_GLOBAL ASM_PFX(gcSmmInitTemplate)
ASM_GLOBAL ASM_PFX(gcSmmInitSize)
ASM_GLOBAL ASM_PFX(mRebasedFlagAddr32)
ASM_GLOBAL ASM_PFX(SmmRelocationSemaphoreComplete)
ASM_GLOBAL ASM_PFX(SmmRelocationSemaphoreComplete32)
ASM_GLOBAL ASM_PFX(mSmmRelocationOriginalAddressPtr32)
ASM_GLOBAL ASM_PFX(gSmmInitStack)
ASM_GLOBAL ASM_PFX(gcSmiInitGdtr)
.text
ASM_PFX(gcSmiInitGdtr):
.word 0
.quad 0
SmmStartup:
.byte 0x66,0xb8 # mov eax, imm32
ASM_PFX(gSmmCr3): .space 4
movq %rax, %cr3
.byte 0x66,0x2e
lgdt (ASM_PFX(gcSmiInitGdtr) - SmmStartup)(%ebp)
.byte 0x66,0xb8 # mov eax, imm32
ASM_PFX(gSmmCr4): .space 4
orb $2, %ah # enable XMM registers access
movq %rax, %cr4
.byte 0x66
movl $0xc0000080,%ecx # IA32_EFER MSR
rdmsr
orb $1,%ah # set LME bit
wrmsr
.byte 0x66,0xb8 # mov eax, imm32
ASM_PFX(gSmmCr0): .space 4
movq %rax, %cr0
.byte 0x66,0xea # far jmp to long mode
ASM_PFX(gSmmJmpAddr): .quad LongMode
LongMode: # long-mode starts here
.byte 0x48,0xbc # mov rsp, imm64
ASM_PFX(gSmmInitStack): .space 8
andw $0xfff0, %sp # make sure RSP is 16-byte aligned
#
# Accoring to X64 calling convention, XMM0~5 are volatile, we need to save
# them before calling C-function.
#
subq $0x60, %rsp
movdqa %xmm0, 0x0(%rsp)
movdqa %xmm1, 0x10(%rsp)
movdqa %xmm2, 0x20(%rsp)
movdqa %xmm3, 0x30(%rsp)
movdqa %xmm4, 0x40(%rsp)
movdqa %xmm5, 0x50(%rsp)
addq $-0x20, %rsp
call ASM_PFX(SmmInitHandler)
addq $0x20, %rsp
#
# Restore XMM0~5 after calling C-function.
#
movdqa 0x0(%rsp), %xmm0
movdqa 0x10(%rsp), %xmm1
movdqa 0x20(%rsp), %xmm2
movdqa 0x30(%rsp), %xmm3
movdqa 0x40(%rsp), %xmm4
movdqa 0x50(%rsp), %xmm5
rsm
ASM_PFX(gcSmmInitTemplate):
_SmmInitTemplate:
.byte 0x66,0x2e,0x8b,0x2e # mov ebp, cs:[@F]
.word L1 - _SmmInitTemplate + 0x8000
.byte 0x66, 0x81, 0xed, 0, 0, 3, 0 # sub ebp, 0x30000
jmp *%bp # jmp ebp actually
L1:
.quad SmmStartup
ASM_PFX(gcSmmInitSize): .word . - ASM_PFX(gcSmmInitTemplate)
ASM_PFX(SmmRelocationSemaphoreComplete):
# Create a simple stack frame to store RAX and the original RSM location
pushq %rax # Used to store return address
pushq %rax
# Load the original RSM location onto stack
movabsq $ASM_PFX(mSmmRelocationOriginalAddress), %rax
movq (%rax), %rax
movq %rax, 0x08(%rsp)
# Update rebase flag
movabsq $ASM_PFX(mRebasedFlag), %rax
movq (%rax), %rax
movb $1, (%rax)
#restore RAX and return to original RSM location
popq %rax
retq
#
# Semaphore code running in 32-bit mode
#
ASM_PFX(SmmRelocationSemaphoreComplete32):
#
# movb $1, ()
#
.byte 0xc6, 0x05
ASM_PFX(mRebasedFlagAddr32):
.long 0
.byte 1
#
# jmpd ()
#
.byte 0xff, 0x25
ASM_PFX(mSmmRelocationOriginalAddressPtr32):
.long 0

View File

@ -0,0 +1,132 @@
;------------------------------------------------------------------------------ ;
; Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
; SmmInit.Asm
;
; Abstract:
;
; Functions for relocating SMBASE's for all processors
;
;-------------------------------------------------------------------------------
EXTERNDEF SmmInitHandler:PROC
EXTERNDEF gSmmCr0:DWORD
EXTERNDEF gSmmCr3:DWORD
EXTERNDEF gSmmCr4:DWORD
EXTERNDEF gSmmJmpAddr:QWORD
EXTERNDEF gcSmmInitTemplate:BYTE
EXTERNDEF gcSmmInitSize:WORD
EXTERNDEF mRebasedFlag:PTR BYTE
EXTERNDEF mSmmRelocationOriginalAddress:QWORD
EXTERNDEF mRebasedFlagAddr32:DWORD
EXTERNDEF mSmmRelocationOriginalAddressPtr32:DWORD
EXTERNDEF gSmmInitStack:QWORD
EXTERNDEF gcSmiInitGdtr:FWORD
.code
gcSmiInitGdtr LABEL FWORD
DW 0
DQ 0
SmmStartup PROC
DB 66h, 0b8h ; mov eax, imm32
gSmmCr3 DD ?
mov cr3, rax
DB 66h, 2eh
lgdt fword ptr [ebp + (offset gcSmiInitGdtr - SmmStartup)]
DB 66h, 0b8h ; mov eax, imm32
gSmmCr4 DD ?
or ah, 2 ; enable XMM registers access
mov cr4, rax
DB 66h
mov ecx, 0c0000080h ; IA32_EFER MSR
rdmsr
or ah, 1 ; set LME bit
wrmsr
DB 66h, 0b8h ; mov eax, imm32
gSmmCr0 DD ?
mov cr0, rax ; enable protected mode & paging
DB 66h, 0eah ; far jmp to long mode
gSmmJmpAddr DQ @LongMode
@LongMode: ; long-mode starts here
DB 48h, 0bch ; mov rsp, imm64
gSmmInitStack DQ ?
and sp, 0fff0h ; make sure RSP is 16-byte aligned
;
; Accoring to X64 calling convention, XMM0~5 are volatile, we need to save
; them before calling C-function.
;
sub rsp, 60h
movdqa [rsp], xmm0
movdqa [rsp + 10h], xmm1
movdqa [rsp + 20h], xmm2
movdqa [rsp + 30h], xmm3
movdqa [rsp + 40h], xmm4
movdqa [rsp + 50h], xmm5
add rsp, -20h
call SmmInitHandler
add rsp, 20h
;
; Restore XMM0~5 after calling C-function.
;
movdqa xmm0, [rsp]
movdqa xmm1, [rsp + 10h]
movdqa xmm2, [rsp + 20h]
movdqa xmm3, [rsp + 30h]
movdqa xmm4, [rsp + 40h]
movdqa xmm5, [rsp + 50h]
rsm
SmmStartup ENDP
gcSmmInitTemplate LABEL BYTE
_SmmInitTemplate PROC
DB 66h, 2eh, 8bh, 2eh ; mov ebp, cs:[@F]
DW @L1 - _SmmInitTemplate + 8000h
DB 66h, 81h, 0edh, 00h, 00h, 03h, 00 ; sub ebp, 30000h
jmp bp ; jmp ebp actually
@L1:
DQ SmmStartup
_SmmInitTemplate ENDP
gcSmmInitSize DW $ - gcSmmInitTemplate
SmmRelocationSemaphoreComplete PROC
push rax
mov rax, mRebasedFlag
mov byte ptr [rax], 1
pop rax
jmp [mSmmRelocationOriginalAddress]
SmmRelocationSemaphoreComplete ENDP
;
; Semaphore code running in 32-bit mode
;
SmmRelocationSemaphoreComplete32 PROC
;
; mov byte ptr [], 1
;
db 0c6h, 05h
mRebasedFlagAddr32 dd 0
db 1
;
; jmp dword ptr []
;
db 0ffh, 25h
mSmmRelocationOriginalAddressPtr32 dd 0
SmmRelocationSemaphoreComplete32 ENDP
END

View File

@ -0,0 +1,316 @@
/** @file
X64 processor specific functions to enable SMM profile.
Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PiSmmCpuDxeSmm.h"
#include "SmmProfileInternal.h"
//
// Current page index.
//
UINTN mPFPageIndex;
//
// Pool for dynamically creating page table in page fault handler.
//
UINT64 mPFPageBuffer;
//
// Store the uplink information for each page being used.
//
UINT64 *mPFPageUplink[MAX_PF_PAGE_COUNT];
/**
Create SMM page table for S3 path.
**/
VOID
InitSmmS3Cr3 (
VOID
)
{
EFI_PHYSICAL_ADDRESS Pages;
UINT64 *PTEntry;
//
// Generate PAE page table for the first 4GB memory space
//
Pages = Gen4GPageTable (1, FALSE);
//
// Fill Page-Table-Level4 (PML4) entry
//
PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (1));
*PTEntry = Pages | PAGE_ATTRIBUTE_BITS;
ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));
//
// Return the address of PML4 (to set CR3)
//
mSmmS3ResumeState->SmmS3Cr3 = (UINT32)(UINTN)PTEntry;
return ;
}
/**
Allocate pages for creating 4KB-page based on 2MB-page when page fault happens.
**/
VOID
InitPagesForPFHandler (
VOID
)
{
VOID *Address;
//
// Pre-Allocate memory for page fault handler
//
Address = NULL;
Address = AllocatePages (MAX_PF_PAGE_COUNT);
ASSERT_EFI_ERROR (Address != NULL);
mPFPageBuffer = (UINT64)(UINTN) Address;
mPFPageIndex = 0;
ZeroMem ((VOID *) (UINTN) mPFPageBuffer, EFI_PAGE_SIZE * MAX_PF_PAGE_COUNT);
ZeroMem (mPFPageUplink, sizeof (mPFPageUplink));
return;
}
/**
Allocate one page for creating 4KB-page based on 2MB-page.
@param Uplink The address of Page-Directory entry.
**/
VOID
AcquirePage (
UINT64 *Uplink
)
{
UINT64 Address;
//
// Get the buffer
//
Address = mPFPageBuffer + EFI_PAGES_TO_SIZE (mPFPageIndex);
ZeroMem ((VOID *) (UINTN) Address, EFI_PAGE_SIZE);
//
// Cut the previous uplink if it exists and wasn't overwritten
//
if ((mPFPageUplink[mPFPageIndex] != NULL) && ((*mPFPageUplink[mPFPageIndex] & PHYSICAL_ADDRESS_MASK) == Address)) {
*mPFPageUplink[mPFPageIndex] = 0;
}
//
// Link & Record the current uplink
//
*Uplink = Address | PAGE_ATTRIBUTE_BITS;
mPFPageUplink[mPFPageIndex] = Uplink;
mPFPageIndex = (mPFPageIndex + 1) % MAX_PF_PAGE_COUNT;
}
/**
Update page table to map the memory correctly in order to make the instruction
which caused page fault execute successfully. And it also save the original page
table to be restored in single-step exception.
@param PageTable PageTable Address.
@param PFAddress The memory address which caused page fault exception.
@param CpuIndex The index of the processor.
@param ErrorCode The Error code of exception.
@param IsValidPFAddress The flag indicates if SMM profile data need be added.
**/
VOID
RestorePageTableAbove4G (
UINT64 *PageTable,
UINT64 PFAddress,
UINTN CpuIndex,
UINTN ErrorCode,
BOOLEAN *IsValidPFAddress
)
{
UINTN PTIndex;
UINT64 Address;
BOOLEAN Nx;
BOOLEAN Existed;
UINTN Index;
UINTN PFIndex;
ASSERT ((PageTable != NULL) && (IsValidPFAddress != NULL));
//
// If page fault address is 4GB above.
//
//
// Check if page fault address has existed in page table.
// If it exists in page table but page fault is generated,
// there are 2 possible reasons: 1. present flag is set to 0; 2. instruction fetch in protected memory range.
//
Existed = FALSE;
PageTable = (UINT64*)(AsmReadCr3 () & PHYSICAL_ADDRESS_MASK);
PTIndex = BitFieldRead64 (PFAddress, 39, 47);
if ((PageTable[PTIndex] & IA32_PG_P) != 0) {
// PML4E
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
PTIndex = BitFieldRead64 (PFAddress, 30, 38);
if ((PageTable[PTIndex] & IA32_PG_P) != 0) {
// PDPTE
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
PTIndex = BitFieldRead64 (PFAddress, 21, 29);
// PD
if ((PageTable[PTIndex] & IA32_PG_PS) != 0) {
//
// 2MB page
//
Address = (UINT64)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
if ((Address & PHYSICAL_ADDRESS_MASK & ~((1ull << 21) - 1)) == ((PFAddress & PHYSICAL_ADDRESS_MASK & ~((1ull << 21) - 1)))) {
Existed = TRUE;
}
} else {
//
// 4KB page
//
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
if (PageTable != 0) {
//
// When there is a valid entry to map to 4KB page, need not create a new entry to map 2MB.
//
PTIndex = BitFieldRead64 (PFAddress, 12, 20);
Address = (UINT64)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
if ((Address & PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1)) == (PFAddress & PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1))) {
Existed = TRUE;
}
}
}
}
}
//
// If page entry does not existed in page table at all, create a new entry.
//
if (!Existed) {
if (IsAddressValid (PFAddress, &Nx)) {
//
// If page fault address above 4GB is in protected range but it causes a page fault exception,
// Will create a page entry for this page fault address, make page table entry as present/rw and execution-disable.
// this access is not saved into SMM profile data.
//
*IsValidPFAddress = TRUE;
}
//
// Create one entry in page table for page fault address.
//
SmiDefaultPFHandler ();
//
// Find the page table entry created just now.
//
PageTable = (UINT64*)(AsmReadCr3 () & PHYSICAL_ADDRESS_MASK);
PFAddress = AsmReadCr2 ();
// PML4E
PTIndex = BitFieldRead64 (PFAddress, 39, 47);
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
// PDPTE
PTIndex = BitFieldRead64 (PFAddress, 30, 38);
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
// PD
PTIndex = BitFieldRead64 (PFAddress, 21, 29);
Address = PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK;
//
// Check if 2MB-page entry need be changed to 4KB-page entry.
//
if (IsAddressSplit (Address)) {
AcquirePage (&PageTable[PTIndex]);
// PTE
PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
for (Index = 0; Index < 512; Index++) {
PageTable[Index] = Address | PAGE_ATTRIBUTE_BITS;
if (!IsAddressValid (Address, &Nx)) {
PageTable[Index] = PageTable[Index] & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
}
if (Nx && mXdSupported) {
PageTable[Index] = PageTable[Index] | IA32_PG_NX;
}
if (Address == (PFAddress & PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1))) {
PTIndex = Index;
}
Address += SIZE_4KB;
} // end for PT
} else {
//
// Update 2MB page entry.
//
if (!IsAddressValid (Address, &Nx)) {
//
// Patch to remove present flag and rw flag.
//
PageTable[PTIndex] = PageTable[PTIndex] & (INTN)(INT32)(~PAGE_ATTRIBUTE_BITS);
}
//
// Set XD bit to 1
//
if (Nx && mXdSupported) {
PageTable[PTIndex] = PageTable[PTIndex] | IA32_PG_NX;
}
}
}
//
// Record old entries with non-present status
// Old entries include the memory which instruction is at and the memory which instruction access.
//
//
ASSERT (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT);
if (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT) {
PFIndex = mPFEntryCount[CpuIndex];
mLastPFEntryValue[CpuIndex][PFIndex] = PageTable[PTIndex];
mLastPFEntryPointer[CpuIndex][PFIndex] = &PageTable[PTIndex];
mPFEntryCount[CpuIndex]++;
}
//
// Add present flag or clear XD flag to make page fault handler succeed.
//
PageTable[PTIndex] |= (UINT64)(PAGE_ATTRIBUTE_BITS);
if ((ErrorCode & IA32_PF_EC_ID) != 0) {
//
// If page fault is caused by instruction fetch, clear XD bit in the entry.
//
PageTable[PTIndex] &= ~IA32_PG_NX;
}
return;
}
/**
Clear TF in FLAGS.
@param SystemContext A pointer to the processor context when
the interrupt occurred on the processor.
**/
VOID
ClearTrapFlag (
IN OUT EFI_SYSTEM_CONTEXT SystemContext
)
{
SystemContext.SystemContextX64->Rflags &= (UINTN) ~BIT8;
}

View File

@ -0,0 +1,105 @@
/** @file
X64 processor specific header file to enable SMM profile.
Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SMM_PROFILE_ARCH_H_
#define _SMM_PROFILE_ARCH_H_
#pragma pack (1)
typedef struct _MSR_DS_AREA_STRUCT {
UINT64 BTSBufferBase;
UINT64 BTSIndex;
UINT64 BTSAbsoluteMaximum;
UINT64 BTSInterruptThreshold;
UINT64 PEBSBufferBase;
UINT64 PEBSIndex;
UINT64 PEBSAbsoluteMaximum;
UINT64 PEBSInterruptThreshold;
UINT64 PEBSCounterReset[2];
UINT64 Reserved;
} MSR_DS_AREA_STRUCT;
typedef struct _BRANCH_TRACE_RECORD {
UINT64 LastBranchFrom;
UINT64 LastBranchTo;
UINT64 Rsvd0 : 4;
UINT64 BranchPredicted : 1;
UINT64 Rsvd1 : 59;
} BRANCH_TRACE_RECORD;
typedef struct _PEBS_RECORD {
UINT64 Rflags;
UINT64 LinearIP;
UINT64 Rax;
UINT64 Rbx;
UINT64 Rcx;
UINT64 Rdx;
UINT64 Rsi;
UINT64 Rdi;
UINT64 Rbp;
UINT64 Rsp;
UINT64 R8;
UINT64 R9;
UINT64 R10;
UINT64 R11;
UINT64 R12;
UINT64 R13;
UINT64 R14;
UINT64 R15;
} PEBS_RECORD;
#pragma pack ()
#define PHYSICAL_ADDRESS_MASK ((1ull << 52) - SIZE_4KB)
/**
Update page table to map the memory correctly in order to make the instruction
which caused page fault execute successfully. And it also save the original page
table to be restored in single-step exception.
@param PageTable PageTable Address.
@param PFAddress The memory address which caused page fault exception.
@param CpuIndex The index of the processor.
@param ErrorCode The Error code of exception.
@param IsValidPFAddress The flag indicates if SMM profile data need be added.
**/
VOID
RestorePageTableAbove4G (
UINT64 *PageTable,
UINT64 PFAddress,
UINTN CpuIndex,
UINTN ErrorCode,
BOOLEAN *IsValidPFAddress
);
/**
Create SMM page table for S3 path.
**/
VOID
InitSmmS3Cr3 (
VOID
);
/**
Allocate pages for creating 4KB-page based on 2MB-page when page fault happens.
**/
VOID
InitPagesForPFHandler (
VOID
);
#endif // _SMM_PROFILE_ARCH_H_

View File

@ -0,0 +1,156 @@
## @file StmCpuPkg.dec
# This Package provides STM compatible CPU modules and libraries.
#
# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials are licensed and made available under
# the terms and conditions of the BSD License which accompanies this distribution.
# The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
DEC_SPECIFICATION = 0x00010005
PACKAGE_NAME = StmCpuPkg
PACKAGE_GUID = 60079593-95E6-4C01-9B39-52F575BA0F49
PACKAGE_VERSION = 0.1
[Includes]
Include
[LibraryClasses.IA32, LibraryClasses.X64]
## @libraryclass Public include file for the SMM CPU Platform Hook Library.
##
SmmCpuPlatformHookLib|Include/Library/SmmCpuPlatformHookLib.h
## @libraryclass Provides the CPU specific programming for PiSmmCpuDxeSmm module.
##
SmmCpuFeaturesLib|Include/Library/SmmCpuFeaturesLib.h
[Guids]
gUefiCpuPkgTokenSpaceGuid = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }}
gStmCpuPkgTokenSpaceGuid = { 0x743a969b, 0x8d64, 0x44c1, { 0x99, 0x70, 0x62, 0x95, 0x13, 0xfc, 0x84, 0x49 }}
gMsegSmramGuid = { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }}
[Protocols]
## Include/Protocol/SmmCpuService.h
gEfiSmmCpuServiceProtocolGuid = { 0x1d202cab, 0xc8ab, 0x4d5c, { 0x94, 0xf7, 0x3c, 0xfc, 0xc0, 0xd3, 0xd3, 0x35 }}
gEfiSmMonitorInitProtocolGuid = { 0x228f344d, 0xb3de, 0x43bb, { 0xa4, 0xd7, 0xea, 0x20, 0xb, 0x1b, 0x14, 0x82 }}
[PcdsFeatureFlag]
## Indicates if SMM Profile will be enabled.
# If enabled, instruction executions in and data accesses to memory outside of SMRAM will be logged.
# This PCD is only for validation purpose. It should be set to false in production.<BR><BR>
# TRUE - SMM Profile will be enabled.<BR>
# FALSE - SMM Profile will be disabled.<BR>
# @Prompt Enable SMM Profile.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileEnable|FALSE|BOOLEAN|0x32132109
## Indicates if the SMM profile log buffer is a ring buffer.
# If disabled, no additional log can be done when the buffer is full.<BR><BR>
# TRUE - the SMM profile log buffer is a ring buffer.<BR>
# FALSE - the SMM profile log buffer is a normal buffer.<BR>
# @Prompt The SMM profile log buffer is a ring buffer.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileRingBuffer|FALSE|BOOLEAN|0x3213210a
## Indicates if SMM Startup AP in a blocking fashion.
# TRUE - SMM Startup AP in a blocking fashion.<BR>
# FALSE - SMM Startup AP in a non-blocking fashion.<BR>
# @Prompt SMM Startup AP in a blocking fashion.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmBlockStartupThisAp|FALSE|BOOLEAN|0x32132108
## Indicates if SMM Stack Guard will be enabled.
# If enabled, stack overflow in SMM can be caught which eases debugging.<BR><BR>
# TRUE - SMM Stack Guard will be enabled.<BR>
# FALSE - SMM Stack Guard will be disabled.<BR>
# @Prompt Enable SMM Stack Guard.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard|FALSE|BOOLEAN|0x1000001C
## Indicates if BSP election in SMM will be enabled.
# If enabled, a BSP will be dynamically elected among all processors in each SMI.
# Otherwise, processor 0 is always as BSP in each SMI.<BR><BR>
# TRUE - BSP election in SMM will be enabled.<BR>
# FALSE - BSP election in SMM will be disabled.<BR>
# @Prompt Enable BSP election in SMM.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|TRUE|BOOLEAN|0x32132106
## Indicates if CPU SMM hot-plug will be enabled.<BR><BR>
# TRUE - SMM CPU hot-plug will be enabled.<BR>
# FALSE - SMM CPU hot-plug will be disabled.<BR>
# @Prompt SMM CPU hot-plug.
gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport|FALSE|BOOLEAN|0x3213210C
## Indicates if SMM Debug will be enabled.
# If enabled, hardware breakpoints in SMRAM can be set outside of SMM mode and take effect in SMM.<BR><BR>
# TRUE - SMM Debug will be enabled.<BR>
# FALSE - SMM Debug will be disabled.<BR>
# @Prompt Enable SMM Debug.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmDebug|FALSE|BOOLEAN|0x1000001B
## Indicates if lock SMM Feature Control MSR.<BR><BR>
# TRUE - SMM Feature Control MSR will be locked.<BR>
# FALSE - SMM Feature Control MSR will not be locked.<BR>
# @Prompt Lock SMM Feature Control MSR.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmFeatureControlMsrLock|TRUE|BOOLEAN|0x3213210B
## Indicates if STM is supported.<BR><BR>
# TRUE - STM is supported.<BR>
# FALSE - STM is unsupported.<BR>
# @Prompt STM supported or not.
gStmCpuPkgTokenSpaceGuid.PcdCpuStmSupport|TRUE|BOOLEAN|0x32132110
[PcdsFixedAtBuild, PcdsPatchableInModule]
## Specifies buffer size in bytes for STM exception stack. The value should be a multiple of 4KB.
# @Prompt STM exception stack size.
gStmCpuPkgTokenSpaceGuid.PcdCpuSmmStmExceptionStackSize|0x1000|UINT32|0x32132111
## Specifies buffer size in bytes of MSEG. The value should be a multiple of 4KB.
# @Prompt MSEG size.
gStmCpuPkgTokenSpaceGuid.PcdCpuMsegSize|0x200000|UINT32|0x32132112
[PcdsFixedAtBuild, PcdsPatchableInModule]
## Specifies buffer size in bytes to save SMM profile data. The value should be a multiple of 4KB.
# @Prompt SMM profile data buffer size.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileSize|0x200000|UINT32|0x32132107
## Specifies stack size in bytes for each processor in SMM.
# @Prompt Processor stack size in SMM.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize|0x2000|UINT32|0x32132105
## Specifies timeout value in microseconds for the BSP in SMM to wait for all APs to come into SMM.
# @Prompt AP synchronization timeout value in SMM.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmApSyncTimeout|1000000|UINT64|0x32132104
## Indicates if SMM Code Access Check is enabled.
# If enabled, the SMM handler cannot execute the code outside SMM regions.
# This PCD is suggested to TRUE in production image.<BR><BR>
# TRUE - SMM Code Access Check will be enabled.<BR>
# FALSE - SMM Code Access Check will be disabled.<BR>
# @Prompt SMM Code Access Check.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmCodeAccessCheckEnable|TRUE|BOOLEAN|0x60000013
## Indicates the CPU synchronization method used when processing an SMI.
# 0x00 - Traditional CPU synchronization method.<BR>
# 0x01 - Relaxed CPU synchronization method.<BR>
# @Prompt SMM CPU Synchronization Method.
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x00|UINT8|0x60000014
[PcdsDynamic, PcdsDynamicEx]
## Contains the pointer to a CPU S3 data buffer of structure ACPI_CPU_DATA.
# @Prompt The pointer to a CPU S3 data buffer.
# @ValidList 0x80000001 | 0
gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress|0x0|UINT64|0x60000010
## Contains the pointer to a CPU Hot Plug Data structure if CPU hot-plug is supported.
# @Prompt The pointer to CPU Hot Plug Data.
# @ValidList 0x80000001 | 0
gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress|0x0|UINT64|0x60000011

View File

@ -0,0 +1,74 @@
## @file
# StmCpuPkg Package
#
# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
PLATFORM_NAME = StmCpu
PLATFORM_GUID = 0B2D0753-077C-4F3B-9859-55668045ECC0
PLATFORM_VERSION = 0.1
DSC_SPECIFICATION = 0x00010005
OUTPUT_DIRECTORY = Build/StmCpu
SUPPORTED_ARCHITECTURES = IA32|X64
BUILD_TARGETS = DEBUG|RELEASE
SKUID_IDENTIFIER = DEFAULT
#
# External libraries to build package
#
[LibraryClasses]
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
MtrrLib|UefiCpuPkg/Library/MtrrLib/MtrrLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
[LibraryClasses.common.DXE_SMM_DRIVER]
SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf
MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf
SmmCpuPlatformHookLib|StmCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
SmmCpuFeaturesLib|StmCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
[PcdsFeatureFlag]
gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE
[Components.IA32, Components.X64]
StmCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf

View File

@ -0,0 +1,113 @@
/** @file
EndOfDxe Protocol on ExitPmAuth Protocol Thunk driver.
Some EDK platform uses ExitPmAuth and DxeSmmReadyToLock without EndOfDxe.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
of the BSD License which accompanies this distribution. The
full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "EndOfDxeOnExitPmAuthThunk.h"
/**
An empty dummy callback function.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
InternalEmptyCallbackFuntion (
IN EFI_EVENT Event,
IN VOID *Context
)
{
return;
}
/**
ExitPmAuth Protocol notification event handler.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
ExitPmAuthProtocolNotification (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
VOID *ExitPmAuth;
EFI_EVENT EndOfDxeEvent;
//
// Add more check to locate protocol after got event, because
// ECP will signal this event immediately once it is register
// just in case it is already installed.
//
Status = gBS->LocateProtocol (
&gExitPmAuthProtocolGuid,
NULL,
&ExitPmAuth
);
if (EFI_ERROR (Status)) {
return ;
}
//
// Since PI1.2.1, we need signal EndOfDxe as ExitPmAuth
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
InternalEmptyCallbackFuntion,
NULL,
&gEfiEndOfDxeEventGroupGuid,
&EndOfDxeEvent
);
ASSERT_EFI_ERROR (Status);
gBS->SignalEvent (EndOfDxeEvent);
gBS->CloseEvent (EndOfDxeEvent);
DEBUG((EFI_D_INFO,"All EndOfDxe callbacks have returned successfully\n"));
}
/**
Entry Point for DxeSmmReadyToLock Protocol on ExitPmAuth Protocol Thunk driver.
@param[in] ImageHandle Image handle of this driver.
@param[in] SystemTable A Pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
**/
EFI_STATUS
EFIAPI
EndOfDxeMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
VOID *Registration;
//
// Install notifications for required protocols
//
EfiCreateProtocolNotifyEvent (
&gExitPmAuthProtocolGuid,
TPL_CALLBACK,
ExitPmAuthProtocolNotification,
NULL,
&Registration
);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,28 @@
/** @file
Include file for EndOfDxe Protocol on ExitPmAuth Protocol Thunk driver.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
of the BSD License which accompanies this distribution. The
full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _END_OF_DXE_ON_EXIT_PMAUTH_THUNK_H_
#define _END_OF_DXE_ON_EXIT_PMAUTH_THUNK_H_
#include <PiDxe.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiLib.h>
#include <Guid/EventGroup.h>
#include <Protocol/ExitPmAuth.h>
#endif

View File

@ -0,0 +1,53 @@
## @file
# Component description file for EndOfDxe Protocol on
# ExitPmAuth Protocol Thunk driver.
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions
# of the BSD License which accompanies this distribution. The
# full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = EndOfDxeOnExitPmAuthThunk
FILE_GUID = 82ECEE48-9571-4427-8485-85A5A45A0F39
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = EndOfDxeMain
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
EndOfDxeOnExitPmAuthThunk.c
EndOfDxeOnExitPmAuthThunk.h
[Packages]
MdePkg/MdePkg.dec
IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
[LibraryClasses]
UefiDriverEntryPoint
UefiBootServicesTableLib
DebugLib
UefiLib
[Guids]
gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
[Protocols]
gExitPmAuthProtocolGuid ## CONSUMES
[Depex]
TRUE

View File

@ -0,0 +1,62 @@
/** @file
Framework SMM CPU Save State protocol on SMST2 Thunk.
This thunk driver produces Framework SMM CPU Save Status Protocol on SMST2.
Some ECP platforms are still using Framework SMM CPU Save Status Protocol.
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiSmm.h>
#include <Protocol/SmmCpuSaveState.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/SmmServicesTableLib.h>
///
/// SMM CPU Save State Protocol instance
///
EFI_SMM_CPU_SAVE_STATE_PROTOCOL mSmmCpuSaveState = {
NULL
};
/**
Entry point of PI SMM Status Code Protocol on Framework SMM Status Code Protocol thunk driver.
@param ImageHandle The firmware allocated handle for the EFI image.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
**/
EFI_STATUS
EFIAPI
SmmCpuSaveStateProtocolOnSmst2Main (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
mSmmCpuSaveState.CpuSaveState = (EFI_SMM_CPU_STATE **)gSmst->CpuSaveState;
Handle = NULL;
Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces(
&Handle,
&gEfiSmmCpuSaveStateProtocolGuid,
&mSmmCpuSaveState,
NULL
);
ASSERT_EFI_ERROR(Status);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,49 @@
## @file
# Framework SMM CPU Save State protocol on SMST2 Thunk.
#
# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SmmCpuSaveStateProtocolOnSmst2
FILE_GUID = B2E23D9B-648D-4D9F-A033-5227706C4539
MODULE_TYPE = DXE_SMM_DRIVER
PI_SPECIFICATION_VERSION = 0x0001000A
VERSION_STRING = 1.0
ENTRY_POINT = SmmCpuSaveStateProtocolOnSmst2Main
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
SmmCpuSaveStateProtocolOnSmst2.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
[LibraryClasses]
SmmServicesTableLib
UefiDriverEntryPoint
DebugLib
BaseLib
[Protocols]
gEfiSmmCpuSaveStateProtocolGuid ## PRODUCES
[Depex]
gEfiSmmCpuProtocolGuid

View File

@ -0,0 +1,218 @@
/** @file
This is the driver that produce MsegSmram hob.
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiPei.h>
#include <Guid/SmramMemoryReserve.h>
#include <Guid/MsegSmram.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PcdLib.h>
/**
Retrieves the data structure associated witht he GUIDed HOB of type gEfiSmmPeiSmramMemoryReserveGuid
@retval NULL A HOB of type gEfiSmmPeiSmramMemoryReserveGuid could not be found.
@retval !NULL A pointer to the GUID data from a HIB of type gEfiSmmPeiSmramMemoryReserveGuid
**/
EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *
GetSrmamHobData (
VOID
)
{
VOID *GuidHob;
//
// Search SmramMemoryReserve HOB that describes SMRAM region
//
GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
if (GuidHob == NULL) {
return NULL;
}
return (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)GET_GUID_HOB_DATA (GuidHob);
}
/**
This routine will split SmramReserve hob to reserve Mseg page for SMRAM content.
@retval EFI_SUCCESS The gEfiSmmPeiSmramMemoryReserveGuid is splited successfully.
@retval EFI_NOT_FOUND The gEfiSmmPeiSmramMemoryReserveGuid is not found.
**/
EFI_STATUS
EFIAPI
SplitSmramReserveHob (
VOID
)
{
EFI_HOB_GUID_TYPE *GuidHob;
EFI_PEI_HOB_POINTERS Hob;
EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;
EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *NewDescriptorBlock;
UINTN BufferSize;
UINTN SmramRanges;
UINT32 MsegSize;
UINT32 MsegBase;
MsegSize = PcdGet32 (PcdCpuMsegSize);
//
// Retrieve the GUID HOB data that contains the set of SMRAM descriptyors
//
GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
if (GuidHob == NULL) {
return EFI_NOT_FOUND;
}
DescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)GET_GUID_HOB_DATA (GuidHob);
//
// Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer
// to the SMM Services Table that is required on the S3 resume path
//
SmramRanges = DescriptorBlock->NumberOfSmmReservedRegions;
BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK) + (SmramRanges * sizeof (EFI_SMRAM_DESCRIPTOR));
Hob.Raw = BuildGuidHob (
&gEfiSmmPeiSmramMemoryReserveGuid,
BufferSize
);
ASSERT (Hob.Raw);
NewDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)Hob.Raw;
//
// Copy old EFI_SMRAM_HOB_DESCRIPTOR_BLOCK to new allocated region
//
CopyMem ((VOID *)Hob.Raw, DescriptorBlock, BufferSize - sizeof(EFI_SMRAM_DESCRIPTOR));
//
// Increase the number of SMRAM descriptors by 1 to make room for the ALLOCATED descriptor of size EFI_PAGE_SIZE
//
NewDescriptorBlock->NumberOfSmmReservedRegions = (UINT32)(SmramRanges + 1);
ASSERT (SmramRanges >= 1);
//
// Copy last entry to the end - we assume TSEG is last entry, which is same assumption as R8 CPU/SMM driver
//
CopyMem (&NewDescriptorBlock->Descriptor[SmramRanges], &NewDescriptorBlock->Descriptor[SmramRanges - 1], sizeof(EFI_SMRAM_DESCRIPTOR));
//
// Reduce the size of the last entry with MsegSize.
//
ASSERT (NewDescriptorBlock->Descriptor[SmramRanges].PhysicalSize > MsegSize);
NewDescriptorBlock->Descriptor[SmramRanges].PhysicalSize -= MsegSize;
//
// Add the last but 1 entry with size of MsegSize and put into the ALLOCATED state
//
MsegBase = (UINT32)(NewDescriptorBlock->Descriptor[SmramRanges].CpuStart + NewDescriptorBlock->Descriptor[SmramRanges].PhysicalSize);
NewDescriptorBlock->Descriptor[SmramRanges - 1].PhysicalStart = MsegBase;
NewDescriptorBlock->Descriptor[SmramRanges - 1].CpuStart = MsegBase;
NewDescriptorBlock->Descriptor[SmramRanges - 1].PhysicalSize = MsegSize;
NewDescriptorBlock->Descriptor[SmramRanges - 1].RegionState |= EFI_ALLOCATED;
//
// Last step, we can scrub old one
//
ZeroMem (&GuidHob->Name, sizeof(GuidHob->Name));
return EFI_SUCCESS;
}
/**
This routine will create MsegSmram hob to hold MsegSmramInfo.
@retval EFI_SUCCESS The MsegSmramHob is created successfully.
@retval EFI_NOT_FOUND The gEfiSmmPeiSmramMemoryReserveGuid is not found.
**/
EFI_STATUS
EFIAPI
CreateMsegSmramHob (
VOID
)
{
EFI_PEI_HOB_POINTERS Hob;
EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;
UINTN SmramRanges;
//
// Retrieve the GUID HOB data that contains the set of SMRAM descriptyors
//
DescriptorBlock = GetSrmamHobData ();
if (DescriptorBlock == NULL) {
return EFI_NOT_FOUND;
}
Hob.Raw = BuildGuidHob (
&gMsegSmramGuid,
sizeof (EFI_SMRAM_DESCRIPTOR)
);
ASSERT (Hob.Raw);
//
// It should be already patch, so just copy last but 1 region directly.
//
SmramRanges = DescriptorBlock->NumberOfSmmReservedRegions;
ASSERT (SmramRanges >= 2);
if (SmramRanges >= 2) {
CopyMem ((VOID *)Hob.Raw, &DescriptorBlock->Descriptor[SmramRanges - 2], sizeof (EFI_SMRAM_DESCRIPTOR));
}
return EFI_SUCCESS;
}
/**
Driver Entry for MsegSmram PEIM
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS Success create gMsegSmramGuid and
split gEfiSmmPeiSmramMemoryReserveGuid.
@retval EFI_NOT_FOUND Can not get gEfiSmmPeiSmramMemoryReserveGuid hob
**/
EFI_STATUS
EFIAPI
MsegSmramHobEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
if (PcdGet32 (PcdCpuMsegSize) == 0) {
return EFI_SUCCESS;
}
//
// Split SmramReserve hob.
//
Status = SplitSmramReserveHob ();
if (EFI_ERROR (Status)) {
return Status;
}
//
// Create MsegSmram hob.
//
Status = CreateMsegSmramHob ();
return Status;
}

View File

@ -0,0 +1,53 @@
## @file
# Component description file for MsegSmramPeim.
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = MsegSmramPeim
FILE_GUID = D2ABC888-AE13-4e3b-BCEE-5DE368FA4E72
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = MsegSmramHobEntry
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
MsegSmramPei.c
[Packages]
MdePkg/MdePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
StmCpuPkg/StmCpuPkg.dec
[LibraryClasses]
PeimEntryPoint
MemoryAllocationLib
DebugLib
HobLib
PeiServicesLib
BaseMemoryLib
[Pcd]
gStmCpuPkgTokenSpaceGuid.PcdCpuMsegSize ## CONSUMES
[Guids]
gEfiSmmPeiSmramMemoryReserveGuid ## CONSUMES ## HOB
gMsegSmramGuid ## PRODUCES ## HOB
[Depex]
gEfiPeiMemoryDiscoveredPpiGuid

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,39 @@
## @file StmPlatformSamplePkg.Sample.fdf
#
# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[FV.FVRECOVERY]
!if $(STM_ENABLE) == TRUE
INF StmPlatformSamplePkg/MsegSmramPei/MsegSmramPei.inf
!endif
[FV.FVMAIN]
!if $(STM_ENABLE) == TRUE
INF StmCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
!else
# original PiSmmCpuDxeSmm.inf
!endif
!if $(STM_ENABLE) == TRUE
INF StmPlatformSamplePkg/StmPlatformSmm/StmPlatformSmm.inf
INF StmPlatformSamplePkg/Compatibility/EndOfDxeOnExitPmAuthThunk/EndOfDxeOnExitPmAuthThunk.inf
INF StmPlatformSamplePkg/Compatibility/SmmCpuSaveStateProtocolOnSmst2/SmmCpuSaveStateProtocolOnSmst2.inf
FILE FREEFORM = PCD(gStmPlatformTokenSpaceGuid.PcdStmBinFile) {
SECTION RAW = StmPlatformSamplePkg/StmBin/X64$(TARGET)/Stm.bin
}
INF USE=X64 StmPlatformSamplePkg/TestBin/X64$(TARGET)/Frm.inf
INF USE=X64 StmPlatformSamplePkg/TestBin/X64$(TARGET)/StmService.inf
INF USE=X64 StmPlatformSamplePkg/TestBin/X64$(TARGET)/FrmLoader.inf
!endif

View File

@ -0,0 +1,26 @@
## @file StmPlatformSamplePkg.dec
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
DEC_SPECIFICATION = 0x00010005
PACKAGE_NAME = StmPlatformSamplePkg
PACKAGE_GUID = C6EEF1B6-499F-4eea-BAF0-4E7C211389DF
PACKAGE_VERSION = 0.1
[Includes.common]
[Guids]
gStmPlatformTokenSpaceGuid = { 0x49a5d4e2, 0x5279, 0x402e, { 0x9a, 0xb1, 0x8d, 0x80, 0xb7, 0xe8, 0x8c, 0xf7 }}
[PcdsFixedAtBuild]
gStmPlatformTokenSpaceGuid.PcdStmBinFile|{ 0x06, 0x3E, 0xCA, 0xAC, 0x64, 0x3C, 0x09, 0x45, 0xA6, 0x87, 0xDD, 0xC7, 0x6F, 0x71, 0xB5, 0x61 }|VOID*|0x20000001

View File

@ -0,0 +1,73 @@
## @file StmPlatformSamplePkg.dsc
#
# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
PLATFORM_NAME = StmPlatformSamplePkg
PLATFORM_GUID = 6F86CFEE-D1B0-4226-BE07-91C7D3B892CC
PLATFORM_VERSION = 0.1
DSC_SPECIFICATION = 0x00010005
OUTPUT_DIRECTORY = Build/StmPlatformSamplePkg
SUPPORTED_ARCHITECTURES = IA32|X64
BUILD_TARGETS = DEBUG|RELEASE
SKUID_IDENTIFIER = DEFAULT
[LibraryClasses]
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf
PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf
IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
SerialPortLib|PcAtChipsetPkg/Library/SerialIoLib/SerialIoLib.inf
DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
[LibraryClasses.common.PEIM]
PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
[LibraryClasses.common.DXE_DRIVER]
[LibraryClasses.common.DXE_SMM_DRIVER]
SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf
OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf
IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
[Components]
StmPlatformSamplePkg/MsegSmramPei/MsegSmramPei.inf
StmPlatformSamplePkg/StmPlatformSmm/StmPlatformSmm.inf
StmPlatformSamplePkg/Compatibility/EndOfDxeOnExitPmAuthThunk/EndOfDxeOnExitPmAuthThunk.inf
StmPlatformSamplePkg/Compatibility/SmmCpuSaveStateProtocolOnSmst2/SmmCpuSaveStateProtocolOnSmst2.inf
[PcdsFixedAtBuild]
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0f
gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000
gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x06

View File

@ -0,0 +1,272 @@
/** @file
STM platform SMM resource
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "StmPlatformSmm.h"
#define RDWR_ACCS 3
#define FULL_ACCS 7
UINT32 mMaxBus;
UINT32 mTsegBase;
UINT32 mTsegSize;
UINT16 mPmBase;
//
// Fixed memory ranges
//
//
// TSEG memory!
//
STM_RSC_MEM_DESC RscTsegMemory = {
{MEM_RANGE, sizeof (STM_RSC_MEM_DESC)},
0,
0,
FULL_ACCS
};
//
// Flash part
//
STM_RSC_MEM_DESC RscSpiMemory = {
{MEM_RANGE, sizeof (STM_RSC_MEM_DESC)},
0xFE000000,
0x01000000,
FULL_ACCS
};
//
// ACPI
//
STM_RSC_IO_DESC RscPmIo = {
{IO_RANGE, sizeof (STM_RSC_IO_DESC)},
0,
128
};
//
// PCIE MMIO
//
STM_RSC_MMIO_DESC RscPcieMmio = {
{MMIO_RANGE, sizeof (STM_RSC_MMIO_DESC)},
0,
0, // Length
RDWR_ACCS
};
//
// Local APIC
//
STM_RSC_MMIO_DESC RscApicMmio = {
{MMIO_RANGE, sizeof (STM_RSC_MMIO_DESC)},
0,
0x400,
RDWR_ACCS
};
//
// Software SMI
//
STM_RSC_TRAPPED_IO_DESC RscSwSmiTrapIo = {
{TRAPPED_IO_RANGE, sizeof (STM_RSC_TRAPPED_IO_DESC)},
0xB2,
2
};
//
// End of list
//
STM_RSC_END RscListEnd = {
{END_OF_RESOURCES, sizeof (STM_RSC_END)},
0
};
//
// Common PCI devices
//
//
// LPC bridge
//
STM_RSC_PCI_CFG_DESC RscLpcBridgePci = {
{PCI_CFG_RANGE, sizeof (STM_RSC_PCI_CFG_DESC)},
RDWR_ACCS, 0,
0,
0x1000,
0,
0,
{
{1, 1, sizeof(STM_PCI_DEVICE_PATH_NODE), LPC_FUNCTION, LPC_DEVICE},
},
};
//
// Template for MSR resources.
//
STM_RSC_MSR_DESC RscMsrTpl = {
{MACHINE_SPECIFIC_REG, sizeof (STM_RSC_MSR_DESC)},
};
//
// MSR indices to register
//
typedef struct {
UINT32 MsrIndex;
UINT64 ReadMask;
UINT64 WriteMask;
} MSR_TABLE_ENTRY;
MSR_TABLE_ENTRY MsrTable[] = {
// Index Read Write // MASK64 means need access, MASK0 means no need access.
{SMRR_PHYSBASE_MSR, MASK64, MASK0},
{SMRR_PHYSMASK_MSR, MASK64, MASK0},
};
/**
Reads a 64-bit PCI configuration register.
@param Address Address that encodes the PCI Bus, Device, Function and
Register.
@return The read value from the PCI configuration register.
**/
UINT64
PciRead64 (
IN UINTN Address
)
{
UINT64 RegLow;
UINT64 RegHigh;
RegLow = (UINT64) PciRead32(Address);
RegHigh = (UINT64) PciRead32(Address + 4);
return (LShiftU64 (RegHigh, 32) + RegLow);
}
/**
BIOS resources initialization.
**/
VOID
ResourceInit (
VOID
)
{
mMaxBus = 255;
mPmBase = (UINT16) PciRead16 (
PCI_LIB_ADDRESS (
LPC_BUS,
LPC_DEVICE,
LPC_FUNCTION,
R_ACPI_PM_BASE)
) & ACPI_PM_BASE_MASK;
mTsegBase = (UINT32)AsmReadMsr64 (SMRR_PHYSBASE_MSR) & 0xFFFFF000;
mTsegSize = (UINT32)(~((UINT32)AsmReadMsr64 (SMRR_PHYSMASK_MSR) & 0xFFFFF000) + 1);
}
/**
Fix up PCIE resource.
**/
VOID
FixupPciexResource (
VOID
)
{
//
// Find max bus number and PCIEX length
//
RscPcieMmio.Length = 0x10000000; // 256 MB
RscPcieMmio.Base = PcdGet64 (PcdPciExpressBaseAddress);
}
/**
Add basic resources to BIOS resource database.
**/
VOID
AddSimpleResources (
VOID
)
{
EFI_STATUS Status;
//
// Fix-up values
//
RscTsegMemory.Base = mTsegBase;
RscTsegMemory.Length = mTsegSize;
RscPmIo.Base = (UINT16) mPmBase;
//
// Local APIC. We assume that all thteads are programmed identically
// despite that it is possible to have individual APIC address for
// each of the threads. If this is the case this programming should
// be corrected.
//
RscApicMmio.Base = AsmReadMsr64 (IA32_APIC_BASE_MSR_INDEX) & 0xFFFFFF000ull;
//
// PCIEX BAR
//
FixupPciexResource ();
Status = mSmMonitorInitProtocol->AddPiResource((VOID *) &RscTsegMemory, 0);
ASSERT_EFI_ERROR (Status);
Status = mSmMonitorInitProtocol->AddPiResource((VOID *) &RscLpcBridgePci, 1);
ASSERT_EFI_ERROR (Status);
}
/**
Add MSR resources to BIOS resource database.
**/
VOID
AddMsrResources (
VOID
)
{
EFI_STATUS Status;
UINT32 Index;
for (Index = 0; Index < sizeof(MsrTable)/sizeof(MsrTable[0]); Index ++) {
RscMsrTpl.MsrIndex = (UINT32) MsrTable[Index].MsrIndex;
RscMsrTpl.ReadMask = (UINT64) MsrTable[Index].ReadMask;
RscMsrTpl.WriteMask = (UINT64) MsrTable[Index].WriteMask;
Status = mSmMonitorInitProtocol->AddPiResource ((VOID *) &RscMsrTpl, 1);
ASSERT_EFI_ERROR (Status);
}
}
/**
Add resources to BIOS resource database.
**/
VOID
AddResourcesCmd (
VOID
)
{
ResourceInit ();
AddSimpleResources();
AddMsrResources ();
}

View File

@ -0,0 +1,47 @@
/** @file
STM platform SMM resource
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _STM_PLATFORM_RESOURCE_H_
#define _STM_PLATFORM_RESOURCE_H_
#define MASK0 0
#define MASK64 0xFFFFFFFFFFFFFFFFull
//
// LPC
//
#define LPC_BUS 0
#define LPC_DEVICE 31
#define LPC_FUNCTION 0
#define R_ACPI_PM_BASE 0x40
#define ACPI_PM_BASE_MASK 0xFFF8
//
// MSRs
//
#define IA32_APIC_BASE_MSR_INDEX 0x1B
#define SMRR_PHYSBASE_MSR 0x1F2
#define SMRR_PHYSMASK_MSR 0x1F3
/**
Add resources to BIOS resource database.
**/
VOID
AddResourcesCmd (
VOID
);
#endif

View File

@ -0,0 +1,128 @@
/** @file
STM platform SMM API
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "StmPlatformSmm.h"
EFI_SM_MONITOR_INIT_PROTOCOL *mSmMonitorInitProtocol;
/**
SMM End Of Dxe event notification handler.
Add system resource for STM.
@param[in] Protocol Points to the protocol's unique identifier.
@param[in] Interface Points to the interface instance.
@param[in] Handle The handle on which the interface was installed.
@retval EFI_SUCCESS Notification handler runs successfully.
**/
EFI_STATUS
EFIAPI
SmmEndOfDxeEventNotify (
IN CONST EFI_GUID *Protocol,
IN VOID *Interface,
IN EFI_HANDLE Handle
)
{
AddResourcesCmd ();
return EFI_SUCCESS;
}
/**
Load STM image.
@retval EFI_SUCCESS STM is loaded to MSEG
@retval EFI_BUFFER_TOO_SMALL MSEG is too small
@retval EFI_UNSUPPORTED MSEG is not enabled
**/
EFI_STATUS
LoadStmImage (
VOID
)
{
EFI_STATUS Status;
VOID *StmImageBuffer;
UINTN StmImageSize;
//
// Extract STM image from FV
//
StmImageBuffer = NULL;
StmImageSize = 0;
Status = GetSectionFromAnyFv (
PcdGetPtr(PcdStmBinFile),
EFI_SECTION_RAW,
0,
&StmImageBuffer,
&StmImageSize
);
ASSERT_EFI_ERROR (Status);
Status = mSmMonitorInitProtocol->LoadMonitor ((EFI_PHYSICAL_ADDRESS)(UINTN)StmImageBuffer, StmImageSize);
DEBUG ((EFI_D_ERROR, "mSmMonitorInitProtocol->LoadMonitor - %r\n", Status));
ASSERT_EFI_ERROR (Status);
gBS->FreePool ((VOID *)((UINTN)StmImageBuffer));
return Status;
}
/**
STM platform SMM driver entry point function.
@param ImageHandle image handle for this driver image
@param SystemTable pointer to the EFI System Table
@retval EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
InstallStmPlatformSmm (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
VOID *Registration;
Status = gSmst->SmmLocateProtocol (
&gEfiSmMonitorInitProtocolGuid,
NULL,
(VOID **)&mSmMonitorInitProtocol
);
if (EFI_ERROR(Status) || (mSmMonitorInitProtocol == NULL)) {
return EFI_UNSUPPORTED;
}
Status = LoadStmImage ();
if (EFI_ERROR (Status)) {
return Status;
}
//
// We have to add resource here because it depends on PCI bus enumeration.
// So we use EndOfDxe event.
//
Status = gSmst->SmmRegisterProtocolNotify (
&gEfiSmmEndOfDxeProtocolGuid,
SmmEndOfDxeEventNotify,
&Registration
);
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,43 @@
/** @file
STM platform SMM API
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _STM_PLATFORM_SMM_H_
#define _STM_PLATFORM_SMM_H_
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DxeServicesLib.h>
#include <Library/SmmServicesTableLib.h>
#include <Library/IoLib.h>
#include <Library/PciLib.h>
#include <Library/PcdLib.h>
#include <Library/DebugLib.h>
#include <Protocol/SmmReadyToLock.h>
#include <Protocol/SmmEndOfDxe.h>
#include <Protocol/SmmCpu.h>
#include <IndustryStandard/Pci30.h>
#include <Protocol/SmMonitorInit.h>
#include <Library/PcdLib.h>
#include "StmPlatformResource.h"
extern EFI_SM_MONITOR_INIT_PROTOCOL *mSmMonitorInitProtocol;
#endif

View File

@ -0,0 +1,62 @@
## @file
# Component description file for StmPlatformSmm module.
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = StmPlatformSmm
FILE_GUID = BC0E8BB2-B69D-41cf-BF57-BB908AB0C5AA
MODULE_TYPE = DXE_SMM_DRIVER
VERSION_STRING = 1.0
PI_SPECIFICATION_VERSION = 0x0001000A
ENTRY_POINT = InstallStmPlatformSmm
[Sources]
StmPlatformSmm.c
StmPlatformSmm.h
StmPlatformResource.c
StmPlatformResource.h
[Packages]
MdePkg/MdePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
StmCpuPkg/StmCpuPkg.dec
StmPlatformSamplePkg/StmPlatformSamplePkg.dec
[LibraryClasses]
UefiDriverEntryPoint
BaseLib
BaseMemoryLib
DebugLib
DxeServicesLib
UefiBootServicesTableLib
SmmServicesTableLib
IoLib
PciLib
IntrinsicLib
[Pcd]
gStmPlatformTokenSpaceGuid.PcdStmBinFile ## CONSUMES
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## CONSUMES
[Protocols]
gEfiSmmCpuProtocolGuid ## CONSUMES
gEfiSmmEndOfDxeProtocolGuid ## CONSUMES
gEfiSmMonitorInitProtocolGuid ## PRODUCES
[Depex]
gEfiSmmCpuProtocolGuid AND
gEfiSmmSwDispatch2ProtocolGuid
[BuildOptions]
MSFT:*_*_*_CC_FLAGS = /Od /GL-

View File

@ -0,0 +1 @@


Binary file not shown.

View File

@ -0,0 +1,29 @@
## @file
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
##
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = Frm
FILE_GUID = 0F50B4B1-C62F-4902-B3AF-E79DBED20109
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
[Binaries.X64]
PE32|Frm.efi|*
DXE_DEPEX|Frm.depex|*
[Depex]
FALSE

View File

@ -0,0 +1,34 @@
## @file
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
##
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = FrmLoader
FILE_GUID = BBA4C424-A903-4c2d-BF4A-C54F4A814CB3
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
[Binaries.X64]
PE32|FrmLoader.efi|*
# DXE_DEPEX|FrmLoader.depex|*
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
#[Depex]
# gEfiCpuArchProtocolGuid AND
# gEfiMpServiceProtocolGuid

View File

@ -0,0 +1 @@


View File

@ -0,0 +1,33 @@
## @file
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
##
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = StmService
FILE_GUID = 04E95A7C-07ED-48A7-9462-0E5B1C3B049F
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
[Binaries.X64]
PE32|StmService.efi|*
DXE_DEPEX|StmService.depex|*
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
[Depex]
TRUE

View File

@ -0,0 +1 @@


Binary file not shown.

View File

@ -0,0 +1,29 @@
## @file
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
##
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = Frm
FILE_GUID = 0F50B4B1-C62F-4902-B3AF-E79DBED20109
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
[Binaries.X64]
PE32|Frm.efi|*
DXE_DEPEX|Frm.depex|*
[Depex]
FALSE

View File

@ -0,0 +1,34 @@
## @file
#
# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
##
##
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = FrmLoader
FILE_GUID = BBA4C424-A903-4c2d-BF4A-C54F4A814CB3
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
[Binaries.X64]
PE32|FrmLoader.efi|*
# DXE_DEPEX|FrmLoader.depex|*
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
#[Depex]
# gEfiCpuArchProtocolGuid AND
# gEfiMpServiceProtocolGuid

Some files were not shown because too many files have changed in this diff Show More