summaryrefslogtreecommitdiff
path: root/Core/EM/Nvme/NvmeSmm/NvmeSmm.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/EM/Nvme/NvmeSmm/NvmeSmm.c')
-rw-r--r--Core/EM/Nvme/NvmeSmm/NvmeSmm.c1127
1 files changed, 1127 insertions, 0 deletions
diff --git a/Core/EM/Nvme/NvmeSmm/NvmeSmm.c b/Core/EM/Nvme/NvmeSmm/NvmeSmm.c
new file mode 100644
index 0000000..538a7f0
--- /dev/null
+++ b/Core/EM/Nvme/NvmeSmm/NvmeSmm.c
@@ -0,0 +1,1127 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2015, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeSmm/NvmeSmm.c 10 12/08/16 4:21a Karthikar $
+//
+// $Revision: 10 $
+//
+// $Date: 12/08/16 4:21a $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeSmm/NvmeSmm.c $
+//
+// 10 12/08/16 4:21a Karthikar
+// [TAG] EIP307568
+// [Category] Bug Fix
+// [Symptom] Legacy Installation and booting fails in
+// (INT)_a_4.6.5.5_NVMe_006
+// [RootCause] Since this NvmeSmm_Support token is not included in
+// Token.h, TransferNvmeDataToSmram() dint get control.
+// [Solution] Added NvmeSmm_Support token in Token.h
+// [Files] NvmeBus.c,NvmeSmm.c,NvmeSmm.sdl
+//
+// 9 11/03/16 5:29a Karthikar
+// [TAG] EIP300640
+// [Category] Improvement
+// [Description] NvmeSmm: Security vulnerability in the NvmeSmm driver
+//
+// 8 2/03/16 2:13a Lavanyap
+// [TAG] EIP254133
+// [Category] New Feature
+// [Description] Modify NVMe driver to avoid repeated FALSE THREAT issue
+// report in Security Advisory.
+// [Files] NvmeSmm.c
+//
+// 7 2/02/16 1:24a Karthikar
+// [TAG] EIP254245
+// [Category] Bug Fix
+// [Symptom] Static code analysis issues found in Aptio4 Nvme module
+// [RootCause] In if condition variable is intialized without proper
+// braces.
+// [Solution] Removed wrong variable initialization
+// from if condition.
+// [Files] NvmeSmm.c
+//
+// 6 5/14/15 2:39a Karthikar
+// [TAG] EIP216763
+// [Category] Improvement
+// [Description] Update the Aptio 4.x Nvme driver to Aptio 5.x Nvme
+// driver Label 05
+// [Files] Nvme.mak,NvmeBus.c, NvmeBus.h, NvmeController.c,
+// NvmePassthru.c,NvmePassthru.h, NvmeSmm.c, NvmExpressPassThru.h,
+// PDiskInfo.h
+//
+// 5 4/20/15 8:52a Anbuprakashp
+// [TAG] EIP214300
+// [Category] Bug Fix
+// [Severity] Normal
+// [Symptom] Nvme device with legacy OS can not resume from S4
+// [RootCause] In Aptio 4.x NvmeSmm Driver, Media buffer in
+// EFI_BLOCK_IO_MEDIA holds invalid memory address( i.e. The memory is not
+// allocated in SMRAM ).
+// [Solution] Memory for Media buffer(EFI_BLOCK_IO_MEDIA) is allocated
+// in SMRAM region
+// [Files] NvmeSmm.c
+//
+// 4 4/08/15 10:07a Anbuprakashp
+// [TAG] EIP212320
+// [Category] Bug Fix
+// [Severity] Critical
+// [Symptom] CPU exception in Nvme Driver if
+// PcdCpuSmmCodeAccessCheckEnable is enabled
+// [RootCause] BootService call shouldn't be used inside SMM function.
+// if PcdCpuSmmCodeAccessCheckEnable is enabled, It causes CPU exception.
+// [Solution] Changes made to avoid BootService call inside SMM function
+// [Files] NvmeSmm.c
+// NvmeBus.c
+// AmiNvmeController.h
+//
+// 3 12/10/14 5:14a Lavanyap
+// [TAG] EIP185327
+// [Category] Improvement
+// [Description] Security Enhancement for SMIHandler in Aptio4.x NVMe
+// Driver
+// [Files] NvmeSmm.mak, NvmeSmm.c, NvmeSmm.h
+//
+// 2 9/23/14 2:32a Anandakrishnanl
+// [TAG] EIP180861
+// [Category] Improvement
+// [Description]
+// Add Legacy Boot support in Aptio 4.x Nvme driver - NON PI 1.2 Support
+// [Files] NvmeBus.c
+// NvmeBus.h
+// NvmeSmm.c
+// NvmeSmm.h
+// NvmeSmm.dxs
+// NvmeSmm.sdl
+//
+// 1 9/04/14 7:54a Anandakrishnanl
+// [TAG] EIP180861
+// [Category] Improvement
+// [Description] Legacy Boot support in Aptio 4.x Nvme driver
+// [Files] NvmeSmm.cif
+// NvmeSmm.mak
+// NvmeSmm.dxs
+// NvmeSmm.sdl
+// NvmeSmm.c
+// NvmeSmm.h
+// NvmeDef.h
+//
+//**********************************************************************
+//**********************************************************************
+//<AMI_FHDR_START>
+//
+// Name: NvmeSmm.c
+//
+// Description: Nvme SMM driver to handle the Nvme device access
+//
+//<AMI_FHDR_END>
+//**********************************************************************
+
+#include "NvmeSmm.h"
+
+EFI_SMM_BASE2_PROTOCOL *gSmmBase2;
+EFI_SMM_SYSTEM_TABLE2 *pSmst2;
+NVME_GLOBAL_DATA *gNvmeData;
+AMI_NVME_CONTROLLER_PROTOCOL *gNvmeController[MAX_NVME_DEVICES] = {0};
+BOOLEAN gFirstAPICall = FALSE;
+
+static EFI_GUID gAmiSmmNvmeCommunicationGuid = AMI_SMM_NVME_COMMUNICATION_GUID;
+
+// ]ApiTable - NVMe API Function Dispatch Table
+
+API_FUNC NvmeMassApiTable[] = {
+ NvmeMassAPIGetDeviceInformation, // Nvme Mass API Sub-Func 00h
+ NvmeMassAPIGetDeviceGeometry, // Nvme Mass API Sub-Func 01h
+ NvmeMassAPIResetDevice, // Nvme Mass API Sub-Func 02h
+ NvmeMassAPIReadDevice, // Nvme Mass API Sub-Func 03h
+ NvmeMassAPIWriteDevice, // Nvme Mass API Sub-Func 04h
+ NvmeMassAPIPass, // Nvme Mass API Sub-Func 05h VerifyDevice
+ NvmeMassAPIPass, // Nvme Mass API Sub-Func 06h FormatDevice
+ NvmeMassAPINotSupported, // Nvme Mass API Sub-Func 07h CommandPassThru
+ NvmeMassAPINotSupported, // Nvme BIOS API function 08h AssignDriveNumber
+ NvmeMassAPINotSupported, // Nvme BIOS API function 09h CheckDevStatus
+ NvmeMassAPINotSupported, // Nvme BIOS API function 0Ah GetDevStatus
+ NvmeMassAPINotSupported // Nvme BIOS API function 0Bh GetDeviceParameters
+};
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: ZeroMemorySmm
+//
+// Description: Clears input Buffer to zero
+//
+// Input:
+// void *Buffer
+// UINTN Size
+//
+// Output:
+// NONE
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+
+void
+ZeroMemorySmm (
+ void *Buffer,
+ UINTN Size
+ )
+{
+ UINT8 *Ptr;
+ Ptr = Buffer;
+ while (Size--) {
+ *(Ptr++) = 0;
+ }
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: GetDevEntry
+//
+// Description: Get the Index# for the DeviceAddress
+//
+// Input:
+// UINT8 DeviceAddress,
+// ACTIVE_NAMESPACE_DATA **ActiveNameSpace
+//
+// Output:
+// NONE
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+
+VOID
+GetDevEntry (
+ UINT8 DeviceAddress,
+ ACTIVE_NAMESPACE_DATA **ActiveNameSpace
+)
+{
+
+ UINT8 Count;
+ EFI_LIST_ENTRY *LinkData;
+ AMI_NVME_CONTROLLER_PROTOCOL *NvmeController;
+
+ // Locate a free slot to copy the pointer
+ for (Count = 0; Count < MAX_NVME_DEVICES; Count++ ){
+ if (gNvmeController[Count]) {
+ NvmeController = gNvmeController[Count];
+
+ if(IsListEmpty(&NvmeController->ActiveNameSpaceList)) {
+ continue;
+ }
+
+ for (LinkData = NvmeController->ActiveNameSpaceList.ForwardLink; \
+ LinkData != &NvmeController->ActiveNameSpaceList;
+ LinkData = LinkData->ForwardLink) {
+
+ *ActiveNameSpace = _CR(LinkData ,ACTIVE_NAMESPACE_DATA, Link);
+ if ((*ActiveNameSpace)->Int13DeviceAddress == DeviceAddress) {
+ return;
+ }
+ }
+ }
+ }
+
+ ActiveNameSpace = NULL;
+ return ;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeMassAPIGetDeviceInformation
+//
+// Description: Return Device information
+//
+// Input:
+// NVME_STRUC *NvmeURP
+//
+// Output:
+// NONE
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+VOID
+NvmeMassAPIGetDeviceInformation (
+ NVME_STRUC *NvmeURP
+)
+{
+
+ NvmeURP->bRetValue = NVME_NOT_SUPPORTED;
+ return;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeMassAPIGetDeviceGeometry
+//
+// Description: Return Device Geometry
+//
+// Input:
+// NVME_STRUC *NvmeURP
+//
+// Output:
+// NONE
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+VOID
+NvmeMassAPIGetDeviceGeometry (
+ NVME_STRUC *NvmeURP
+)
+{
+ NvmeURP->bRetValue = NVME_NOT_SUPPORTED;
+ return;
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeMassAPIResetDevice
+//
+// Description: Reset device
+//
+// Input:
+// NVME_STRUC *NvmeURP
+//
+// Output:
+// NONE
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+VOID
+NvmeMassAPIResetDevice (
+ NVME_STRUC *NvmeURP
+)
+{
+ NvmeURP->bRetValue = NVME_NOT_SUPPORTED;
+ return;
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeMassAPIReadDevice
+//
+// Description: Read data from the device
+//
+// Input:
+// NVME_STRUC *NvmeURP
+//
+// Output:
+// NONE
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+VOID
+NvmeMassAPIReadDevice (
+ NVME_STRUC *NvmeURP
+)
+{
+ ACTIVE_NAMESPACE_DATA *ActiveNameSpace = NULL;
+ EFI_STATUS Status;
+ EFI_LBA Lba;
+ UINT16 NumBlks;
+ UINT16 BlksPerTransfer;
+ VOID *Buffer = NULL;
+ VOID *ReadBuffer;
+ UINTN BufferSize;
+ BOOLEAN UnalignedTransfer = FALSE;
+ AMI_NVME_CONTROLLER_PROTOCOL *NvmeController;
+ UINT32 Offset;
+ COMPLETION_QUEUE_ENTRY *pCmdCompletionData;
+
+ GetDevEntry(NvmeURP->ApiData.Read.DeviceAddress, &ActiveNameSpace);
+
+ if(ActiveNameSpace == NULL) {
+ NvmeURP->bRetValue = NVME_PARAMETER_FAILED;
+ return;
+ }
+
+ // Validate if input Buffer address is an non-SMRAM region to avoid SMRAM data
+ // corruption through SMI handlers.
+ // NOTE: As DMA transfer isn't supported inside SMM, Buffer validation is not needed for
+ // NVMe. But below validation code is added to avoid repeated Security False Threat reports.
+
+ Status = AmiValidateMemoryBuffer((VOID*)NvmeURP->ApiData.Read.BufferAddress,
+ NvmeURP->ApiData.Read.NumBlks *
+ ActiveNameSpace->NvmeBlockIO.Media->BlockSize );
+ if (EFI_ERROR(Status)) {
+ NvmeURP->bRetValue = NVME_PARAMETER_FAILED;
+ return;
+ }
+
+ NvmeController = ActiveNameSpace->NvmeController;
+ if (NvmeController->Queue1SubmissionQueueTailPtr == 0xFFFF) {
+ Offset = QUEUE_DOORBELL_OFFSET( NvmeController->NVMQueueNumber, 1, NvmeController->DoorBellStride);
+ NvmeController->Queue1CompletionQueueHeadPtr = CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset);
+ NvmeController->Queue1SubmissionQueueHeadPtr = NvmeController->Queue1CompletionQueueHeadPtr;
+ NvmeController->Queue1SubmissionQueueTailPtr = NvmeController->Queue1CompletionQueueHeadPtr;
+ // Check if there is a roller over
+ if (NvmeController->Queue1SubmissionQueueTailPtr >= NvmeController->Queue1SubmissionQueueSize) {
+ NvmeController->Queue1SubmissionQueueTailPtr = 0;
+ }
+
+ // Update the phase tag from the Completion queue
+ pCmdCompletionData = (COMPLETION_QUEUE_ENTRY *)NvmeController->Queue1CompletionQueueMappedAddr;
+ NvmeController->Queue1PhaseTag = (UINT8)pCmdCompletionData->PhaseTag;
+ NvmeController->CommandIdentifierQueue1 = 0;
+ NvmeController->CommandIdentifierAdmin = 0;
+ }
+
+
+ Lba=NvmeURP->ApiData.Read.LBA;
+ NumBlks=NvmeURP->ApiData.Read.NumBlks;
+
+ (UINT32)Buffer= NvmeURP->ApiData.Read.BufferAddress;
+
+ BlksPerTransfer = NumBlks;
+ ReadBuffer = Buffer;
+
+ //If Buffer isn't aligned use internal buffer
+ if ((UINTN)NvmeURP->ApiData.Read.BufferAddress & ((1 << ActiveNameSpace->NvmeBlockIO.Media->IoAlign)-1)) {
+ BlksPerTransfer = 1;
+ ReadBuffer = NvmeController->LegacyNvmeBuffer;
+ UnalignedTransfer = TRUE;
+ }
+
+ BufferSize = BlksPerTransfer * ActiveNameSpace->NvmeBlockIO.Media->BlockSize;
+
+ for ( ; NumBlks; NumBlks -= BlksPerTransfer){
+ Status = NvmeReadWriteBlocks (ActiveNameSpace, ActiveNameSpace->NvmeBlockIO.Media->MediaId, Lba, BufferSize, ReadBuffer, NULL, NVME_READ);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ if (UnalignedTransfer) {
+ MemCpy (Buffer, ReadBuffer, BufferSize);
+ }
+ (UINTN)Buffer = (UINTN)Buffer + BufferSize;
+ Lba += BlksPerTransfer;
+
+ }
+
+ if (EFI_ERROR(Status)) {
+ NvmeURP->bRetValue = NVME_READ_ERR;
+ } else {
+ NvmeURP->bRetValue = NVME_SUCCESS;
+ }
+
+ return;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeMassAPIWriteDevice
+//
+// Description: Write data to the device
+//
+// Input:
+// NVME_STRUC *NvmeURP
+//
+// Output:
+// NONE
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+VOID
+NvmeMassAPIWriteDevice (
+ NVME_STRUC *NvmeURP
+)
+{
+ ACTIVE_NAMESPACE_DATA *ActiveNameSpace = NULL;
+ EFI_STATUS Status;
+ EFI_LBA Lba;
+ UINT16 NumBlks;
+ UINT16 BlksPerTransfer;
+ VOID *Buffer = NULL;
+ VOID *ReadBuffer;
+ UINTN BufferSize;
+ BOOLEAN UnalignedTransfer = FALSE;
+ AMI_NVME_CONTROLLER_PROTOCOL *NvmeController;
+ UINT32 Offset;
+ COMPLETION_QUEUE_ENTRY *pCmdCompletionData;
+
+ GetDevEntry(NvmeURP->ApiData.Read.DeviceAddress, &ActiveNameSpace);
+
+ if(ActiveNameSpace == NULL) {
+ NvmeURP->bRetValue = NVME_PARAMETER_FAILED;
+ return;
+ }
+
+ // Validate if input Buffer address is an non-SMRAM region to avoid SMRAM data
+ // corruption through SMI handlers.
+ // NOTE: As DMA transfer isn't supported inside SMM, Buffer validation is not needed for
+ // NVMe. But below validation code is added to avoid repeated Security False Threat reports.
+
+ Status = AmiValidateMemoryBuffer((VOID*)NvmeURP->ApiData.Read.BufferAddress,
+ NvmeURP->ApiData.Read.NumBlks *
+ ActiveNameSpace->NvmeBlockIO.Media->BlockSize );
+ if (EFI_ERROR(Status)) {
+ NvmeURP->bRetValue = NVME_PARAMETER_FAILED;
+ return;
+ }
+
+ NvmeController = ActiveNameSpace->NvmeController;
+ if (NvmeController->Queue1SubmissionQueueTailPtr == 0xFFFF) {
+ Offset = QUEUE_DOORBELL_OFFSET( NvmeController->NVMQueueNumber, 1, NvmeController->DoorBellStride);
+ NvmeController->Queue1CompletionQueueHeadPtr = CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset);
+ NvmeController->Queue1SubmissionQueueHeadPtr = NvmeController->Queue1CompletionQueueHeadPtr;
+ NvmeController->Queue1SubmissionQueueTailPtr = NvmeController->Queue1CompletionQueueHeadPtr;
+ // Check if there is a roller over
+ if (NvmeController->Queue1SubmissionQueueTailPtr >= NvmeController->Queue1SubmissionQueueSize) {
+ NvmeController->Queue1SubmissionQueueTailPtr = 0;
+ }
+
+ // Update the phase tag from the Completion queue
+ pCmdCompletionData = (COMPLETION_QUEUE_ENTRY *)NvmeController->Queue1CompletionQueueMappedAddr;
+ NvmeController->Queue1PhaseTag = (UINT8)pCmdCompletionData->PhaseTag;
+ NvmeController->CommandIdentifierQueue1 = 0;
+ NvmeController->CommandIdentifierAdmin = 0;
+
+ }
+
+
+ Lba=NvmeURP->ApiData.Read.LBA;
+ NumBlks=NvmeURP->ApiData.Read.NumBlks;
+
+ (UINT32)Buffer= NvmeURP->ApiData.Read.BufferAddress;
+
+ BlksPerTransfer = NumBlks;
+ ReadBuffer = Buffer;
+
+ //If Buffer isn't aligned use internal buffer
+ if ((UINTN)NvmeURP->ApiData.Read.BufferAddress & ((1 << ActiveNameSpace->NvmeBlockIO.Media->IoAlign)-1)) {
+ BlksPerTransfer = 1;
+ ReadBuffer = NvmeController->LegacyNvmeBuffer;
+ UnalignedTransfer = TRUE;
+ }
+
+ BufferSize = BlksPerTransfer * ActiveNameSpace->NvmeBlockIO.Media->BlockSize;
+
+ for ( ; NumBlks; NumBlks -= BlksPerTransfer){
+
+ if (UnalignedTransfer) {
+ MemCpy (ReadBuffer, Buffer, BufferSize);
+ }
+
+ Status = NvmeReadWriteBlocks (ActiveNameSpace, ActiveNameSpace->NvmeBlockIO.Media->MediaId, Lba, BufferSize, ReadBuffer, NULL, NVME_WRITE);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+
+ (UINTN)Buffer = (UINTN)Buffer + BufferSize;
+ Lba += BlksPerTransfer;
+
+ }
+
+ if (EFI_ERROR(Status)) {
+ NvmeURP->bRetValue = NVME_WRITE_ERR;
+ }
+ else {
+ NvmeURP->bRetValue = NVME_SUCCESS;
+ }
+
+ return;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeMassAPIPass
+//
+// Description: Dummy handler to return NVME_SUCCESS
+//
+// Input:
+// NVME_STRUC *NvmeURP
+//
+// Output:
+// NONE
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+VOID
+NvmeMassAPIPass(
+ NVME_STRUC *NvmeURP
+)
+{
+
+ NvmeURP->bRetValue = NVME_SUCCESS;
+ return;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeMassAPINotSupported
+//
+// Description: Dummy handler to return NVME_NOT_SUPPORTED
+//
+// Input:
+// NVME_STRUC *NvmeURP
+//
+// Output:
+// NONE
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+VOID
+NvmeMassAPINotSupported (
+ NVME_STRUC *NvmeURP
+)
+{
+
+ NvmeURP->bRetValue = NVME_NOT_SUPPORTED;
+ return;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeInitSmmData
+//
+// Description: Initialize NVMe SMM data area
+//
+// Input:
+//
+//
+//
+// Output:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+EFI_STATUS
+EFIAPI
+NvmeInitSmmData (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+#else
+EFI_STATUS
+NvmeInitSmmData (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
+)
+#endif
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ ACTIVE_NAMESPACE_DATA *OrgActiveNameSpace;
+ ACTIVE_NAMESPACE_DATA *ActiveNameSpace;
+ AMI_NVME_CONTROLLER_PROTOCOL *NvmeController;
+ AMI_NVME_CONTROLLER_PROTOCOL *OrgNvmeController;
+ UINT8 Count;
+ EFI_LIST_ENTRY *LinkData;
+ UINTN NvmeComBuffer = 0;
+ static EFI_GUID gNvmeSmmGuid = NVME_SMM_GUID;
+ UINTN VariableSize = sizeof(UINTN);
+ EFI_BLOCK_IO_MEDIA *Media = NULL;
+
+ // After the first API call is invoked, don't initialize SMM data area. This is an additional
+ // Security check so that data won't get corrupted.
+ if (gFirstAPICall) {
+ return EFI_SUCCESS;
+ }
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+
+ // If input is invalid, stop processing this SMI
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+ (UINTN)OrgNvmeController = *(UINTN *)CommBuffer;
+#else
+
+ Status = pRS->GetVariable ( L"NvmeSmmBuffer",
+ &gNvmeSmmGuid,
+ NULL,
+ &VariableSize,
+ &NvmeComBuffer );
+
+// TRACE((-1, "NvmeComBuffer in NvmeInitSmmData = %x\n", NvmeComBuffer));
+
+ (UINTN)OrgNvmeController = NvmeComBuffer;
+
+#endif
+
+
+ // Locate a free slot to copy the pointer
+ for (Count = 0; Count < MAX_NVME_DEVICES; Count++ ){
+ if (!gNvmeController[Count]) {
+ break;
+ }
+ }
+
+ if (Count == MAX_NVME_DEVICES) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+ Status = pSmst2->SmmAllocatePool (
+#else
+ Status = pSmst->SmmAllocatePool (
+#endif
+ EfiRuntimeServicesData,
+ sizeof (AMI_NVME_CONTROLLER_PROTOCOL),
+ (VOID**)&NvmeController);
+ ASSERT_EFI_ERROR(Status);
+
+ // Copy input NvmeController passed in OrgNvmeController into SMM
+ MemCpy ((VOID *)NvmeController, OrgNvmeController, sizeof (AMI_NVME_CONTROLLER_PROTOCOL));
+
+
+ // Copy IDENTIFY_CONTROLLER_DATA
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+ Status = pSmst2->SmmAllocatePool (
+#else
+ Status = pSmst->SmmAllocatePool (
+#endif
+ EfiRuntimeServicesData,
+ sizeof (IDENTIFY_CONTROLLER_DATA),
+ (VOID**)&(NvmeController->IdentifyControllerData));
+ ASSERT_EFI_ERROR(Status);
+
+ MemCpy (NvmeController->IdentifyControllerData, OrgNvmeController->IdentifyControllerData, sizeof(IDENTIFY_CONTROLLER_DATA));
+
+ gNvmeController[Count] = NvmeController;
+
+
+ // Initialize some of the pointers to NULL which aren't applicable during runtime
+ NvmeController->PciIO = NULL;
+ NvmeController->NvmeInSmm = TRUE;
+ NvmeController->Queue1SubmissionQueueTailPtr = 0xFFFF;
+
+ InitializeListHead (&NvmeController->ActiveNameSpaceList);
+
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+ Status = pSmst2->SmmAllocatePool (
+#else
+ Status = pSmst->SmmAllocatePool (
+#endif
+ EfiRuntimeServicesData,
+ sizeof (NVME_COMMAND_WRAPPER),
+ (VOID**)&(NvmeController->NvmeCmdWrapper));
+
+ // Clear memory
+ ZeroMemorySmm (NvmeController->NvmeCmdWrapper, sizeof(NVME_COMMAND_WRAPPER));
+
+ // use original NVMe buffer for this as original address value is used.
+ // Update the NvmeController pointer inside ActiveNameSpace
+ for (LinkData = OrgNvmeController->ActiveNameSpaceList.ForwardLink;
+ LinkData != &OrgNvmeController->ActiveNameSpaceList;
+ LinkData = LinkData->ForwardLink) {
+
+ OrgActiveNameSpace = _CR(LinkData ,ACTIVE_NAMESPACE_DATA, Link);
+
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+ Status = pSmst2->SmmAllocatePool (
+#else
+ Status = pSmst->SmmAllocatePool (
+#endif
+ EfiRuntimeServicesData,
+ sizeof (ACTIVE_NAMESPACE_DATA),
+ (VOID**)&(ActiveNameSpace));
+ if(EFI_ERROR(Status)) {
+ ASSERT_EFI_ERROR(Status);
+ return Status;
+ }
+
+ MemCpy (ActiveNameSpace, OrgActiveNameSpace, sizeof(ACTIVE_NAMESPACE_DATA));
+
+ ActiveNameSpace->NvmeController = NvmeController;
+ ActiveNameSpace->EfiDevicePath = NULL;
+ ActiveNameSpace->UDeviceName = NULL;
+
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+ Status = pSmst2->SmmAllocatePool (
+#else
+ Status = pSmst->SmmAllocatePool (
+#endif
+ EfiRuntimeServicesData,
+ sizeof (EFI_BLOCK_IO_MEDIA),
+ (VOID**)&(Media) );
+ if(EFI_ERROR(Status)) {
+ ASSERT_EFI_ERROR(Status);
+ return Status;
+ }
+
+ MemCpy ( Media, OrgActiveNameSpace->NvmeBlockIO.Media, sizeof(EFI_BLOCK_IO_MEDIA) );
+ ActiveNameSpace->NvmeBlockIO.Media = Media;
+
+ InsertTailList (&NvmeController->ActiveNameSpaceList, &ActiveNameSpace->Link);
+
+ }
+
+ return Status;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeSWSMIHandler
+//
+// Description: Handle SWSMI generated from NVMe CSM16 module
+//
+// Input:
+//
+//
+// Output:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+EFI_STATUS
+NvmeSWSMIHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *DispatchContext OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+)
+#else
+EFI_STATUS
+NvmeSWSMIHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
+)
+#endif
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ NVME_STRUC *NvmeURP=NULL;
+ UINT8 bFuncIndex;
+ UINT8 bNumberOfFunctions;
+ UINT16 EbdaSeg;
+
+ gFirstAPICall = TRUE;
+
+ //
+ // Get the fpURP pointer from EBDA
+ //
+
+ EbdaSeg = *((UINT16*)0x40E);
+ NvmeURP = *(NVME_STRUC**)(UINTN)(((UINT32)EbdaSeg << 4) + NVME_DATA_EBDA_OFFSET);
+ NvmeURP = (NVME_STRUC*)((UINTN)NvmeURP & 0xFFFFFFFF);
+
+ // Validate if URP address is an non-SMRAM region to avoid SMRAM data
+ // corruption through SMI handlers
+ Status = AmiValidateMemoryBuffer((VOID*)NvmeURP, sizeof(NVME_STRUC));
+ if (EFI_ERROR(Status)) {
+ return EFI_SUCCESS;
+ }
+
+ if (NvmeURP->bFuncNumber != NVME_API_MASS_DEVICE_REQUEST) {
+ NvmeURP->bRetValue = NVME_PARAMETER_FAILED;
+ return Status;
+ }
+
+ bFuncIndex = NvmeURP->bSubFunc;
+ bNumberOfFunctions = sizeof NvmeMassApiTable / sizeof (API_FUNC *);
+
+ //
+ // Make sure function number is valid; if function number is not zero
+ // check for valid extended SDIO API function
+ //
+ if (bFuncIndex >= bNumberOfFunctions ) {
+ NvmeURP->bRetValue = NVME_PARAMETER_FAILED;
+ return Status;
+ }
+
+ //
+ // Call the appropriate function
+ //
+
+ NvmeMassApiTable[bFuncIndex](NvmeURP);
+
+ return Status;
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: InSmmFunction
+//
+// Description: Nvme InSmmFunction
+//
+// Input:
+// IN EFI_HANDLE ImageHandle,
+// IN EFI_SYSTEM_TABLE *SystemTable
+//
+// Output:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+InSmmFunction(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EFI_STATUS Status;
+ EFI_HANDLE SwHandle = NULL;
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+ EFI_SMM_SW_REGISTER_CONTEXT SwContext;
+ EFI_HANDLE DispatchHandle;
+ EFI_SMM_SW_DISPATCH2_PROTOCOL *pSwDispatch = NULL;
+#else
+ EFI_SMM_BASE_PROTOCOL *pSmmBase;
+ EFI_SMM_SW_DISPATCH_PROTOCOL *pSwDispatch = NULL;
+ EFI_SMM_SYSTEM_TABLE *pSmst;
+ EFI_SMM_SW_DISPATCH_CONTEXT NvmeSmmSwContext = { NVME_SWSMI };
+ EFI_SMM_SW_DISPATCH_CONTEXT SwContext;
+#endif
+
+ InitAmiBufferValidationLib(ImageHandle, SystemTable);
+
+#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014)
+
+ // PI_1.2 -->>
+
+ Status = pBS->LocateProtocol(&gEfiSmmBase2ProtocolGuid, NULL, &gSmmBase2);
+ if (EFI_ERROR(Status)) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gSmmBase2->GetSmstLocation (gSmmBase2, &pSmst2);
+ if (EFI_ERROR(Status)) {
+ return EFI_SUCCESS;
+ }
+
+ Status = pSmst2->SmmLocateProtocol(&gEfiSmmSwDispatch2ProtocolGuid,
+ NULL,
+ &pSwDispatch);
+ if (EFI_ERROR(Status)) {
+ return EFI_SUCCESS;
+ }
+
+ SwContext.SwSmiInputValue = NVME_SWSMI;
+ Status = pSwDispatch->Register (pSwDispatch,
+ NvmeSWSMIHandler,
+ &SwContext,
+ &SwHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ //Allocate Memory for NVMe global Data.
+ //
+ Status = pSmst2->SmmAllocatePool(EfiRuntimeServicesData,sizeof(NVME_GLOBAL_DATA), &gNvmeData);
+ ASSERT_EFI_ERROR(Status);
+ //
+ // Clear the Buffer
+ //
+ pBS->SetMem((VOID*)gNvmeData, sizeof(NVME_GLOBAL_DATA), 0);
+
+
+ //
+ // Register Nvme handler to transfer data from DXE driver to SMM
+ //
+ Status = pSmst2->SmiHandlerRegister (
+ NvmeInitSmmData,
+ &gAmiSmmNvmeCommunicationGuid,
+ &DispatchHandle
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ // PI_1.2 <<--
+#else
+
+ // NON PI 1.2 -->>
+
+ Status = pBS->LocateProtocol(&gEfiSmmSwDispatchProtocolGuid, NULL, &pSwDispatch);
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = pBS->LocateProtocol(&gEfiSmmBaseProtocolGuid, NULL, &pSmmBase);
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ pSmmBase->GetSmstLocation (pSmmBase, &pSmst);
+
+ Status = pSwDispatch->Register (pSwDispatch,
+ NvmeSWSMIHandler,
+ &NvmeSmmSwContext,
+ &SwHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ //Allocate Memory for NVMe global Data.
+ //
+ Status = pSmst->SmmAllocatePool(EfiRuntimeServicesData,sizeof(NVME_GLOBAL_DATA), &gNvmeData);
+ ASSERT_EFI_ERROR(Status);
+ //
+ // Clear the Buffer
+ //
+ pBS->SetMem((VOID*)gNvmeData, sizeof(NVME_GLOBAL_DATA), 0);
+
+ SwContext.SwSmiInputValue = NVME_INIT_SMM_SWSMI;
+ Status = pSwDispatch->Register (pSwDispatch,
+ NvmeInitSmmData,
+ &SwContext,
+ &SwHandle);
+
+ // NON PI_1.2 <<--
+
+#endif
+
+ return EFI_SUCCESS;
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: NvmeSmmDriverEntryPoint
+//
+// Description: Loads NVMe SMM module into SMM and registers SMI handler
+//
+// Input:
+// IN EFI_HANDLE ImageHandle,
+// IN EFI_SYSTEM_TABLE *SystemTable
+//
+// Output:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: None
+//
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+NvmeSmmDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+
+ InitAmiLib(ImageHandle, SystemTable);
+ return InitSmmHandler (ImageHandle, SystemTable, InSmmFunction, NULL);
+
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2015, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************