diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /Core/EM/Nvme | |
download | zprj-master.tar.xz |
Diffstat (limited to 'Core/EM/Nvme')
32 files changed, 9871 insertions, 0 deletions
diff --git a/Core/EM/Nvme/Nvme.chm b/Core/EM/Nvme/Nvme.chm Binary files differnew file mode 100644 index 0000000..1d8fee0 --- /dev/null +++ b/Core/EM/Nvme/Nvme.chm diff --git a/Core/EM/Nvme/Nvme.cif b/Core/EM/Nvme/Nvme.cif new file mode 100644 index 0000000..0b43f6e --- /dev/null +++ b/Core/EM/Nvme/Nvme.cif @@ -0,0 +1,24 @@ +<component> + name = "Nvme" + category = eModule + LocalRoot = "Core\EM\Nvme\" + RefName = "Nvme" +[files] +"Nvme.sdl" +"Nvme.mak" +"Nvme.sd" +"Nvme.uni" +"Nvme.chm" +"NvmeSetup.c" +"NvmeBus.c" +"NvmePassthru.c" +"NvmeComponentName.c" +"NvmeIncludes.h" +"NvmeBus.h" +"NvmePassthru.h" +[parts] +"NvmeControllerLib" +"NvmeSmm" +"NVMEINT13" +"NvmeProtocol" +<endComponent> diff --git a/Core/EM/Nvme/Nvme.mak b/Core/EM/Nvme/Nvme.mak new file mode 100644 index 0000000..4e9feb6 --- /dev/null +++ b/Core/EM/Nvme/Nvme.mak @@ -0,0 +1,170 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* +#************************************************************************* +# $Header: /Alaska/SOURCE/Modules/NVMe/Nvme.mak 4 5/18/15 2:52a Karthikar $ +# +# $Date: 5/18/15 2:52a $ +# +# $Log: /Alaska/SOURCE/Modules/NVMe/Nvme.mak $ +# +# 4 5/18/15 2:52a 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 +# +# 3 5/14/15 2:38a Karthikar +# +# 2 9/04/14 7:31a Anandakrishnanl +# [TAG] EIP180861 +# [Category] Improvement +# [Description] Legacy Boot support in Aptio 4.x Nvme driver +# [Files] +# Nvme.cif +# Nvme.mak +# Nvme.uni +# Nvme.chm +# NvmeSetup.c +# NvmeBus.c +# NvmeComponentName.c +# NvmeIncludes.h +# NvmeBus.h +# [NvmeControllerLib] +# [NvmeSmm] +# [NVMEINT13] +# [NvmeProtocol] +# +# 1 6/20/14 6:27a Anandakrishnanl +# [TAG] EIP172958 +# [Category] New Feature +# [Description] Nvme Driver Intial Checkin +# [Files] Nvme.cif +# Nvme.sdl +# Nvme.mak +# Nvme.sd +# Nvme.uni +# Nvme.chm +# NvmeSetup.c +# NvmeBus.c +# NvmeController.c +# NvmeComponentName.c +# NvmeIncludes.h +# NvmeBus.h +# NvmeController.h +# +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/NVMe/Nvme.mak $ +# +# 4 5/18/15 2:52a 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 +# +# 3 5/14/15 2:38a Karthikar +# +# 2 9/04/14 7:31a Anandakrishnanl +# [TAG] EIP180861 +# [Category] Improvement +# [Description] Legacy Boot support in Aptio 4.x Nvme driver +# [Files] +# Nvme.cif +# Nvme.mak +# Nvme.uni +# Nvme.chm +# NvmeSetup.c +# NvmeBus.c +# NvmeComponentName.c +# NvmeIncludes.h +# NvmeBus.h +# [NvmeControllerLib] +# [NvmeSmm] +# [NVMEINT13] +# [NvmeProtocol] +# +# 1 6/20/14 6:27a Anandakrishnanl +# [TAG] EIP172958 +# [Category] New Feature +# [Description] Nvme Driver Intial Checkin +# [Files] Nvme.cif +# Nvme.sdl +# Nvme.mak +# Nvme.sd +# Nvme.uni +# Nvme.chm +# NvmeSetup.c +# NvmeBus.c +# NvmeController.c +# NvmeComponentName.c +# NvmeIncludes.h +# NvmeBus.h +# NvmeController.h +# +#************************************************************************* +#<AMI_FHDR_START> +# +# Name: Nvme.mak +# +# Description: +# +#<AMI_FHDR_END> +#************************************************************************ +all : Nvme + +Nvme : $(BUILD_DIR)\Nvme.mak NvmeBin + +$(BUILD_DIR)\Nvme.mak : $(NVME_DIR)\$(@B).cif $(NVME_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(NVME_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +NvmeBin: $(AMIDXELIB) $(NVMECONTROLLERLIB) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\Nvme.mak all\ + GUID=634E8DB5-C432-43BE-A653-9CA2922CC458\ + ENTRY_POINT=NvmeBusEntryPoint \ + TYPE=BS_DRIVER \ + COMPRESS=1 HAS_RESOURCES=1\ + "OBJECTS=$(BUILD_DIR)\$(NVME_DIR)\NvmeBus.obj\ + $(BUILD_DIR)\$(NVME_DIR)\NvmeComponentName.obj\ + $(BUILD_DIR)\$(NVME_DIR)\NvmePassthru.obj" + +SetupSdbs :$(BUILD_DIR)\Nvme.mak NVMESDB +SetupBin : $(BUILD_DIR)\NvmeSetup.obj + +NVMESDB : + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\Nvme.mak all\ + TYPE=SDB NAME=Nvme MAKEFILE=$(BUILD_DIR)\Nvme.mak\ + "STRING_CONSUMERS=$(NVME_DIR)\Nvme.sd $(NVME_DIR)\NvmeSetup.c " + +$(BUILD_DIR)\NvmeSetup.obj : $(NVME_DIR)\NvmeSetup.c $(BUILD_DIR)\SetupStrTokens.h + $(CC) $(CFLAGS) /Fo$(BUILD_DIR)\ $(NVME_DIR)\NvmeSetup.c +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/Core/EM/Nvme/Nvme.sd b/Core/EM/Nvme/Nvme.sd new file mode 100644 index 0000000..327bf96 --- /dev/null +++ b/Core/EM/Nvme/Nvme.sd @@ -0,0 +1,170 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (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/Nvme.sd 2 5/19/15 5:03a Ksudarsanan $ +// +// $Date: 5/19/15 5:03a $ +// +// $Log: /Alaska/SOURCE/Modules/NVMe/Nvme.sd $ +// +// 2 5/19/15 5:03a Ksudarsanan +// [TAG] EIP218818 +// [Category] Improvement +// [Description] Aptio 4.x: When NVMe device is not connect then in BIOS +// Setup should display "No Nvme device found" +// [Files] Nvme.sd, Nvme.uni, NvmeSetup.c +// +// 1 6/20/14 6:27a Anandakrishnanl +// [TAG] EIP172958 +// [Category] New Feature +// [Description] Nvme Driver Intial Checkin +// [Files] Nvme.cif +// Nvme.sdl +// Nvme.mak +// Nvme.sd +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeController.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// NvmeController.h +// +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/Nvme.sd $ +// +// 2 5/19/15 5:03a Ksudarsanan +// [TAG] EIP218818 +// [Category] Improvement +// [Description] Aptio 4.x: When NVMe device is not connect then in BIOS +// Setup should display "No Nvme device found" +// [Files] Nvme.sd, Nvme.uni, NvmeSetup.c +// +// 1 6/20/14 6:27a Anandakrishnanl +// [TAG] EIP172958 +// [Category] New Feature +// [Description] Nvme Driver Intial Checkin +// [Files] Nvme.cif +// Nvme.sdl +// Nvme.mak +// Nvme.sd +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeController.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// NvmeController.h +// +//************************************************************************* +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: Nvme.sd +// +// Description: Nvme Driver Setup Page +// +//<AMI_FHDR_END> +//********************************************************************** + +#ifdef FORM_SET_TYPEDEF +#include "Token.h" +#endif + +#ifdef SETUP_DATA_DEFINITION +// These definitions will be converted by the build process +// to a definitions of SETUP_DATA fields. + UINT8 ShowNVMeDrive[4]; + UINT8 DeviceCount; +#endif + + +#if defined(VFRCOMPILE) && !defined(CONTROLS_ARE_DEFINED) + #define CONTROL_DEFINITION +#endif + +#ifdef CONTROL_DEFINITION + #define NVMe_INFO_DISPLAY(HELP_STRING, CONTROLLER_STRING, DEVICE_STRING,INDEX)\ + suppressif ideqval SETUP_DATA.ShowNVMeDrive[INDEX] == 0; \ + text \ + help = HELP_STRING, \ + text = CONTROLLER_STRING, \ + text = DEVICE_STRING, \ + flags = 0, \ + key = 0;\ + endif; +#endif + +//Select Top level menu itmem (forset) for you pages +#ifdef ADVANCED_FORM_SET + + #ifdef FORM_SET_GOTO + // Define forms + + // Define goto commands for the forms defined in this file + goto NVME_CONFIG_FORM_ID, + prompt = STRING_TOKEN (STR_NVME_CONFIG_FORM), + help = STRING_TOKEN (STR_NVME_CONFIG_FORM_HELP); + + #endif + + #ifdef FORM_SET_FORM + + #ifndef NVME_FORM_NVME_CONFIG + #define NVME_FORM_NVME_CONFIG + + form formid = AUTO_ID(NVME_CONFIG_FORM_ID), + title = STRING_TOKEN (STR_NVME_CONFIG_FORM); + + SUBTITLE(STRING_TOKEN(STR_NVME_SUBTITLE_STRING)) + SEPARATOR + + NVMe_INFO_DISPLAY( STRING_TOKEN(STR_NVME_HELP_STRING), STRING_TOKEN(STR_NVME0_CONTROLLER), STRING_TOKEN(STR_NVME0_NAME),0) + NVMe_INFO_DISPLAY( STRING_TOKEN(STR_NVME_HELP_STRING), STRING_TOKEN(STR_NVME1_CONTROLLER), STRING_TOKEN(STR_NVME1_NAME),1) + NVMe_INFO_DISPLAY( STRING_TOKEN(STR_NVME_HELP_STRING), STRING_TOKEN(STR_NVME2_CONTROLLER), STRING_TOKEN(STR_NVME2_NAME),2) + NVMe_INFO_DISPLAY( STRING_TOKEN(STR_NVME_HELP_STRING), STRING_TOKEN(STR_NVME3_CONTROLLER), STRING_TOKEN(STR_NVME3_NAME),3) + + suppressif NOT ideqval SETUP_DATA.DeviceCount == 0; + SUBTITLE(STRING_TOKEN(STR_NO_NVME_DEVICE)) + endif; + + endform; // End of NVME_CONFIG_FORM_ID + + #endif // End of NVME_FORM_NVME_CONFIG + + #endif // End of FORM_SET_FORM + +#endif // End of ADVANCED_FORM_SET + + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//**********************************************************************
\ No newline at end of file diff --git a/Core/EM/Nvme/Nvme.sdl b/Core/EM/Nvme/Nvme.sdl new file mode 100644 index 0000000..982578f --- /dev/null +++ b/Core/EM/Nvme/Nvme.sdl @@ -0,0 +1,83 @@ +TOKEN + Name = "NVMe_SUPPORT" + Value = "1" + Help = "Main switch to enable NVMe support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes + Master = Yes +End + +TOKEN + Name = "NVME_VERBOSE_PRINT" + Value = "0" + Help = "Token to Enable/Disable Versbose Mode." + TokenType = Integer + TargetH = Yes +End + +PATH + Name = "NVME_DIR" +End + +TOKEN + Name = "NVME_SETUP" + Value = "1" + Help = "Enable if NVMe setup controls from NVME eModule needs to be displayd in setup" + TokenType = Integer + TargetH = Yes +End + +TOKEN + Name = "NVME_BUS_DRIVER_VERSION" + Value = "1" + Help = "NVMe Bus driver version # reported in Driver Binding Protocol" + TokenType = Integer + TargetH = Yes +End + +MODULE + Help = "Includes Nvme.mak to Project" + File = "Nvme.mak" +End + +ELINK + Name = "$(BUILD_DIR)\Nvme.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + +ELINK + Name = "$(BUILD_DIR)\Nvme.sdb" + Parent = "SETUP_SDBS" + InvokeOrder = AfterParent +End + +ELINK + Name = "$(NVME_DIR)\Nvme.sd" + Parent = "SETUP_DEFINITIONS" + InvokeOrder = AfterParent + Token = "NVME_SETUP" "=" "1" +End + +ELINK + Name = "$(NVME_DIR)\NvmeSetup.c" + Parent = "SetupCallbackFiles" + InvokeOrder = AfterParent + Token = "NVME_SETUP" "=" "1" +End + +ELINK + Name = "InitNvmeStrings," + Parent = "SetupStringInit" + InvokeOrder = AfterParent + Token = "NVME_SETUP" "=" "1" +End + +ELINK + Name = "$(NVME_DIR)\Nvme.uni" + Parent = "SetupStringFiles" + InvokeOrder = AfterParent + Token = "NVME_SETUP" "=" "1" +End + diff --git a/Core/EM/Nvme/Nvme.uni b/Core/EM/Nvme/Nvme.uni Binary files differnew file mode 100644 index 0000000..4f931cb --- /dev/null +++ b/Core/EM/Nvme/Nvme.uni diff --git a/Core/EM/Nvme/NvmeBus.c b/Core/EM/Nvme/NvmeBus.c new file mode 100644 index 0000000..dd921fc --- /dev/null +++ b/Core/EM/Nvme/NvmeBus.c @@ -0,0 +1,2793 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeBus.c 8 12/08/16 4:17a Karthikar $ +// +// $Revision: 8 $ +// +// $Date: 12/08/16 4:17a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeBus.c $ +// +// 8 12/08/16 4:17a 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 +// +// 7 3/17/16 10:25a Anbuprakashp +// [TAG] EIP258388 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Build error when disable CSM_SUPPORT token +// [RootCause] NvmeSmm driver is dependent on NvmeInt13 driver which is +// disabled if CSM_SUPPORT token is off. +// [Solution] NvmeSmm driver will be disabled if CSM_SUPPORT, +// NVMEINT13_SUPPORT sdl tokens are OFF. +// [Files] NvmeSmm.sdl, +// NvmeBus.c +// +// 6 5/14/15 2:38a Karthikar +// +// 5 4/08/15 10:21a 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 +// +// 4 3/09/15 2:51a Rameshr +// [TAG] EIP202328 +// [Category] Improvement +// [Description] IO Completion Size decided based on the size reported +// by device. +// [Files] NvmeBus.c +// +// 3 9/23/14 2:28a 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 +// +// +// 2 9/04/14 7:34a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// [Files] +// Nvme.cif +// Nvme.mak +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// [NvmeControllerLib] +// [NvmeSmm] +// [NVMEINT13] +// [NvmeProtocol] +// +// 1 6/20/14 6:27a Anandakrishnanl +// [TAG] EIP172958 +// [Category] New Feature +// [Description] Nvme Driver Intial Checkin +// [Files] Nvme.cif +// Nvme.sdl +// Nvme.mak +// Nvme.sd +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeController.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// NvmeController.h +// +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeBus.c +// +// Description: Provides Nvme Block IO protocol +// +//<AMI_FHDR_END> +//********************************************************************** + +#include "NvmeIncludes.h" +#include "NvmeBus.h" +#include "NvmePassthru.h" +#include <EFI.h> +#include <AmiLib.h> +#include <AmiDxeLib.h> +#include <Protocol\DevicePath.h> +#include <Protocol\BlockIo.h> + +#ifndef EFI_COMPONENT_NAME2_PROTOCOL_GUID +EFI_GUID gComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID; +#else +EFI_GUID gComponentNameProtocolGuid = EFI_COMPONENT_NAME2_PROTOCOL_GUID; +#endif + +// Used by NVMe legacy boot support +UINT8 gInt13DeviceAddress = 1; +VOID *gLegacyNvmeBuffer = NULL; + +#if (EFI_SPECIFICATION_VERSION > 0x00020000) +extern EFI_COMPONENT_NAME2_PROTOCOL gNvmeBusControllerDriverName; +#else +extern EFI_COMPONENT_NAME_PROTOCOL gNvmeBusControllerDriverName; +#endif + +EFI_GUID gEfiDiskInfoNvmeInterfaceGuid = EFI_DISK_INFO_NVME_INTERFACE_GUID; +EFI_GUID gEfiDiskInfoProtocolGuid = EFI_DISK_INFO_PROTOCOL_GUID; +static EFI_GUID gAmiNvmeControllerProtocolGuid = AMI_NVME_CONTROLLER_PROTOCOL_GUID; +static EFI_GUID gAmiNvmePassThruProtocolGuid = AMI_NVME_PASS_THRU_PROTOCOL_GUID; +static EFI_GUID gAmiNvmeLegacyProtocolGuid = AMI_NVME_LEGACY_PROTOCOL_GUID; +static EFI_GUID gAmiSmmNvmeCommunicationGuid = AMI_SMM_NVME_COMMUNICATION_GUID; +EFI_GUID gEfiNvmExpressPassThruProtocolGuid = EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL_GUID; + +EFI_DRIVER_BINDING_PROTOCOL gNvmeBusDriverBinding = { + NvmeBusSupported, + NvmeBusStart, + NvmeBusStop, + NVME_BUS_DRIVER_VERSION, // version + NULL, // ImageHandle + NULL // DriverBindingHandle +}; + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeBusEntryPoint +// +// Description: Installs gNvmeBusDriverBinding protocol +// +// Input: +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: InitAmiLib InstallMultipleProtocolInterfaces DListInit +// +// Notes: +// Here is the control flow of this function: +// 1. Initialize Ami Lib. +// 2. Install Driver Binding Protocol +// 3. Return EFI_SUCCESS. +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeBusEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // Print Verbose messages + // Enable NVME_VERBOSE_PRINT in SDL file. Make sure PcdDebugPrintErrorLevel + // is set to PcdsPatchableInModule. Sometime is it is overridden in Platform SDL. + // So change it accordingly. + + + gNvmeBusDriverBinding.DriverBindingHandle = NULL; + gNvmeBusDriverBinding.ImageHandle=ImageHandle; + + InitAmiLib(ImageHandle, SystemTable); + + Status = pBS->InstallMultipleProtocolInterfaces( + &gNvmeBusDriverBinding.DriverBindingHandle, + &gEfiDriverBindingProtocolGuid,&gNvmeBusDriverBinding, + &gEfiComponentName2ProtocolGuid, &gNvmeBusControllerDriverName, + NULL + ); + + return Status; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeBusSupported +// +// Description: Checks whether it is a Nvme controller or not. +// If 'yes', return SUCCESS else ERROR +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN EFI_HANDLE Controller, +// IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +// +// Output: +// EFI_STATUS +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeBusSupported( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) +{ + + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIO; + PCI_TYPE00 PciConfig; + + // Check for Valid SATA Device Path. If no return UNSUPPORTED + // Check if Controller is Nvme or not? + + Status = pBS->OpenProtocol( Controller, + &gEfiPciIoProtocolGuid, + (VOID **)&PciIO, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIO->Pci.Read ( PciIO, + EfiPciIoWidthUint8, + 0, + sizeof (PCI_TYPE00), + &PciConfig + ); + + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + // Check for MASS Storage controller, Non-Volatile and NVMHCI interface + if (IS_CLASS3 (&PciConfig, + PCI_CLASS_MASS_STORAGE, + PCI_CLASS_MASS_STORAGE_SOLID_STATE, + PCI_IF_MASS_STORAGE_SOLID_STATE_ENTERPRISE_NVMHCI)) { + + return EFI_SUCCESS; + + } + + return EFI_UNSUPPORTED; +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeBusStart +// +// Description: Installs Nvme Block IO Protocol +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN EFI_HANDLE Controller, +// IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeBusStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +) +{ + + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIO; + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController = NULL; + IDENTIFY_CONTROLLER_DATA *IdentifyData = NULL; + UINT32 *ActiveNameSpaceIDs = NULL; + UINT32 i; + AMI_NVME_PASS_THRU_PROTOCOL *AmiNvmePassThru; + NVM_EXPRESS_PASS_THRU_INSTANCE *NvmePassthruInstance = NULL; + EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *EfiNvmExpressPassThru; + + PROGRESS_CODE(EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_INIT); + + // Get the PciIO interface + Status = pBS->OpenProtocol( Controller, + &gEfiPciIoProtocolGuid, + (VOID **)&PciIO, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER); + + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + + TRACE((-1,"\nNVMe Driver Detection and Configuratiion starts\n")); + + // Do Controller Init + Status = InitializeNvmeController(Controller, This->DriverBindingHandle, &NvmeController); + + if (EFI_ERROR(Status)) { + goto Error_Path; + } + + // Get the IdentifyData + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof (IDENTIFY_CONTROLLER_DATA), + (VOID**)&IdentifyData + ); + + if (EFI_ERROR(Status)) { + goto Error_Path_1; + } + + pBS->SetMem(IdentifyData, sizeof(IDENTIFY_CONTROLLER_DATA), 0); + NvmeController->IdentifyControllerData = IdentifyData; + + // Get IdentifyController Data Structure + Status = GetIdentifyData (NvmeController, (UINT8 *)IdentifyData, 1, 0); + if (EFI_ERROR(Status)) { + goto Error_Path_1; + } + + // Get the list of Active Namespace IDs + Status = pBS->AllocatePages ( + AllocateAnyPages, + EfiRuntimeServicesData, + EFI_SIZE_TO_PAGES(4096), + (EFI_PHYSICAL_ADDRESS*)&(ActiveNameSpaceIDs)); + + if (EFI_ERROR(Status)) { + goto Error_Path_1; + } + + pBS->SetMem(ActiveNameSpaceIDs, 4096, 0); + + NvmeController->ActiveNameSpaceIDs = ActiveNameSpaceIDs; + + // Since "Get list of Active NameSpace IDs" isn't working + // use alternate method to get the active name space. Zero is reserved + for (i=1; i < IdentifyData->NN + 1; i++ ) { + ActiveNameSpaceIDs[i] = i; + } + + Status = EnumerateActiveNameSpace (NvmeController); + if (EFI_ERROR(Status)) { + goto Error_Path_1; + } + + // Is there any active name space discovered + if(IsListEmpty(&NvmeController->ActiveNameSpaceList)) { + goto exit_NvmeBusStart; + } + + // Create Submission and Completion Queue1 + NvmeController->NVMQueueNumber = 1; + Status = CreateAdditionalSubmissionCompletionQueue(NvmeController, + NvmeController->NvmeCmdWrapper, + NvmeController->NVMQueueNumber, + NvmeController->MaxQueueEntrySupported >= QUEUE1_SIZE ? QUEUE1_SIZE : NvmeController->MaxQueueEntrySupported + ); + if (EFI_ERROR(Status)) { + goto Error_Path; + } + Status = InstallBlockIoDiskInfo(This, NvmeController); + if (EFI_ERROR(Status)) { + goto Error_Path_1; + } + + // Install NvmePassThru protocol + Status = pBS->OpenProtocol( + Controller, + &gAmiNvmePassThruProtocolGuid, + (VOID **)&AmiNvmePassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR(Status)) { + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof(AMI_NVME_PASS_THRU_PROTOCOL), + (VOID**)&AmiNvmePassThru + ); + if (!EFI_ERROR(Status)) { + AmiNvmePassThru->ExecuteNvmeCmd = ExecuteNvmeCmd; + pBS->InstallMultipleProtocolInterfaces( + &Controller, + &gAmiNvmePassThruProtocolGuid, + AmiNvmePassThru, + NULL + ); + } + + } + // Installing EfiNvmExpressPassthru protocol + Status = pBS->OpenProtocol( + Controller, + &gEfiNvmExpressPassThruProtocolGuid, + (VOID **)&EfiNvmExpressPassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if ( EFI_ERROR(Status) ) { + // Allocate memory for NVM_EXPRESS_PASS_THRU_INSTANCE structure + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof(NVM_EXPRESS_PASS_THRU_INSTANCE), + (VOID**)&NvmePassthruInstance + ); + + if( !EFI_ERROR(Status) ) { + + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof(EFI_NVM_EXPRESS_PASS_THRU_MODE), + (VOID**)&NvmePassthruInstance->EfiNvmExpressPassThru.Mode + ); + if(EFI_ERROR(Status)) { + pBS->FreePool(NvmePassthruInstance); + } + } + + if (!EFI_ERROR(Status)) { + + EfiNvmExpressPassThru = (EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL*)&(NvmePassthruInstance->EfiNvmExpressPassThru); + + NvmePassthruInstance->NvmeControllerProtocol = NvmeController; + NvmePassthruInstance->ControllerHandle = Controller; + + EfiNvmExpressPassThru->Mode->Attributes = EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL | + EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVME; + EfiNvmExpressPassThru->Mode->IoAlign = 2; // DWORD aligned + EfiNvmExpressPassThru->Mode->NvmeVersion = 0; + EfiNvmExpressPassThru->PassThru = NvmePassThru; + EfiNvmExpressPassThru->GetNextNamespace = GetNextNamespace; + EfiNvmExpressPassThru->BuildDevicePath = BuildDevicePath; + EfiNvmExpressPassThru->GetNameSpace = GetNamespace; + + pBS->InstallMultipleProtocolInterfaces( &NvmePassthruInstance->ControllerHandle, + &gEfiNvmExpressPassThruProtocolGuid, + &NvmePassthruInstance->EfiNvmExpressPassThru, + NULL + ); + } + } + +exit_NvmeBusStart: + TRACE((-1,"\nNVMe Driver Detection and Configuratiion Ends with Status = EFI_SUCCESS\n")); + return EFI_SUCCESS; +Error_Path_1: + // Uninstall NvmeController + pBS->UninstallMultipleProtocolInterfaces( + Controller, + &gAmiNvmeControllerProtocolGuid, + NvmeController, + NULL + ); +Error_Path: + pBS->CloseProtocol ( Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller); + TRACE((-1,"\nNVMe Driver Detection and Configuratiion Ends with Status %r\n", Status)); + return Status; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeBusStop +// +// Description: Uninstall all devices installed in start procedure. +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN EFI_HANDLE Controller, +// IN UINTN NumberOfChildren, +// IN EFI_HANDLE *ChildHandleBuffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: OpenProtocol CloseProtocol +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeBusStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + + EFI_STATUS Status; + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController; + ACTIVE_NAMESPACE_DATA *ActiveNameSpace; + UINTN Index = 0; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + NVME_DEVICE_PATH *NvmeDevicePath; + EFI_LIST_ENTRY *LinkData; + EFI_LIST_ENTRY *ForwardLink; + AMI_NVME_PASS_THRU_PROTOCOL *AmiNvmePassThru; + EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmExpressPassthruProtocol; + NVM_EXPRESS_PASS_THRU_INSTANCE *NvmePassthruInstance = NULL; + + // Check if gAmiNvmeControllerProtocolGuid is installed on the device + Status = pBS->OpenProtocol( Controller, + &gAmiNvmeControllerProtocolGuid, + (VOID **)&NvmeController, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Check if ChildHandleBuffer is valid + // + if (NumberOfChildren) { + while (NumberOfChildren) { + // Does the child handle have the correct devicepath + Status = pBS->OpenProtocol( + ChildHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID **)&DevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + // Locate Nvme devicepath + NvmeDevicePath = (NVME_DEVICE_PATH *) DevicePath; + + while (!isEndNode((EFI_DEVICE_PATH_PROTOCOL *)NvmeDevicePath)) { + + //NvmeDevicePath = (NVME_DEVICE_PATH *)DPNextInstance (&((EFI_DEVICE_PATH_PROTOCOL *)(NvmeDevicePath)), NULL); + if (NvmeDevicePath && NvmeDevicePath->Header.Type == MESSAGING_DEVICE_PATH && \ + NvmeDevicePath->Header.SubType == MSG_NVME_DP){ + + for (LinkData = NvmeController->ActiveNameSpaceList.ForwardLink; \ + LinkData != &NvmeController->ActiveNameSpaceList; + ) { + + ActiveNameSpace = _CR(LinkData, ACTIVE_NAMESPACE_DATA, Link); + + // Is it the correct ActiveNameSpace + if (ActiveNameSpace->IdentifyNamespaceData.EUI64 == NvmeDevicePath->EUI64 && \ + ActiveNameSpace->ActiveNameSpaceID == NvmeDevicePath->Nsid ) { + + // Uninstall and close the protocols + Status = pBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + ChildHandleBuffer[Index]); + + if (EFI_ERROR(Status)) { + continue; + } + + // Check if BlockIO is installed + Status = pBS->OpenProtocol( ChildHandleBuffer[Index], + &gEfiBlockIoProtocolGuid, + NULL, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + + if (Status == EFI_SUCCESS) { + Status = pBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiBlockIoProtocolGuid, + &(ActiveNameSpace->NvmeBlockIO), + NULL); + } + // Check if DiskInfo is installed + Status = pBS->OpenProtocol( ChildHandleBuffer[Index], + &gEfiDiskInfoProtocolGuid, + NULL, + This->DriverBindingHandle, + ChildHandleBuffer[Index], + EFI_OPEN_PROTOCOL_TEST_PROTOCOL ); + + if (Status == EFI_SUCCESS) { + Status = pBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiDiskInfoProtocolGuid, + &(ActiveNameSpace->NvmeDiskInfo), + NULL); + } + + Status = pBS->UninstallMultipleProtocolInterfaces ( + ChildHandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + ActiveNameSpace->EfiDevicePath, + NULL); + + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } else { + // Delete from the list +// RemoveEntryList(&(ActiveNameSpace->Link)); + + // Free up all the memory + NvmeController->PciIO->Unmap(NvmeController->PciIO, + ActiveNameSpace->PRP2ListUnMap + ); + + if (ActiveNameSpace->PRP2List) { + NvmeController->PciIO->FreeBuffer (NvmeController->PciIO, + EFI_SIZE_TO_PAGES(NvmeController->MemoryPageSize),\ + ActiveNameSpace->PRP2List + ); + } + + pBS->FreePool (ActiveNameSpace->NvmeBlockIO.Media); + pBS->FreePool (ActiveNameSpace->EfiDevicePath); + + if (ActiveNameSpace->UDeviceName) { + pBS->FreePool (ActiveNameSpace->UDeviceName->Language); + pBS->FreePool (ActiveNameSpace->UDeviceName->UnicodeString); + pBS->FreePool (ActiveNameSpace->UDeviceName); + } + + ForwardLink = LinkData->ForwardLink; + RemoveEntryList (LinkData); + LinkData = ForwardLink; + pBS->FreePool (ActiveNameSpace); + } + } + + } + + break; + } + + (EFI_DEVICE_PATH_PROTOCOL *)NvmeDevicePath = NEXT_NODE ((EFI_DEVICE_PATH_PROTOCOL *)NvmeDevicePath); + } + Index++; + NumberOfChildren --; + } + } else { + // Check if all Active namespace has been stopped + if(!IsListEmpty(&NvmeController->ActiveNameSpaceList)) { + return EFI_DEVICE_ERROR; + } + // No child is active. + // Stop the controller. This will delete all the Queues. + CONTROLLER_REG32_AND(NvmeController->NvmeBarOffset, Offset_CC, 0xFFFFFFFE); + + Status = pBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gAmiNvmeControllerProtocolGuid, + NvmeController, + NULL); + ASSERT_EFI_ERROR(Status); + Status = pBS->OpenProtocol( Controller, + &gAmiNvmePassThruProtocolGuid, + (VOID **)&AmiNvmePassThru, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!EFI_ERROR(Status)) { + Status = pBS->UninstallMultipleProtocolInterfaces( + Controller, + &gAmiNvmePassThruProtocolGuid, + AmiNvmePassThru, + NULL + ); + + ASSERT_EFI_ERROR(Status); + } + Status = pBS->OpenProtocol( Controller, + &gEfiNvmExpressPassThruProtocolGuid, + (VOID **)&NvmExpressPassthruProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!EFI_ERROR(Status)) { + + Status = pBS->UninstallMultipleProtocolInterfaces( + Controller, + &gEfiNvmExpressPassThruProtocolGuid, + NvmExpressPassthruProtocol, + NULL + ); + + ASSERT_EFI_ERROR(Status); + NvmePassthruInstance = _CR( NvmExpressPassthruProtocol ,NVM_EXPRESS_PASS_THRU_INSTANCE, EfiNvmExpressPassThru); + pBS->FreePool (NvmePassthruInstance->EfiNvmExpressPassThru.Mode); + pBS->FreePool (NvmePassthruInstance); + } + + // Uninstall and close the protocols + Status = pBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller); + + ASSERT_EFI_ERROR(Status); + + // Free up all the memory allocated + if (NvmeController->IdentifyControllerData) { + pBS->FreePool (NvmeController->IdentifyControllerData); + } + + if (NvmeController->IdentifyControllerData) { + pBS->FreePages ((EFI_PHYSICAL_ADDRESS)NvmeController->ActiveNameSpaceIDs, + EFI_SIZE_TO_PAGES(4096) + ); + } + + if (NvmeController->AdminSubmissionQueueUnMap) { + NvmeController->PciIO->Unmap (NvmeController->PciIO, + NvmeController->AdminSubmissionQueueUnMap + ); + } + if (NvmeController->AdminSubmissionUnAligned) { + NvmeController->PciIO->FreeBuffer (NvmeController->PciIO, \ + EFI_SIZE_TO_PAGES(NvmeController->AdminSubmissionUnAlignedSize), \ + (VOID *)NvmeController->AdminSubmissionUnAligned + ); + } + + if (NvmeController->AdminCompletionQueueUnMap) { + NvmeController->PciIO->Unmap (NvmeController->PciIO, + NvmeController->AdminCompletionQueueUnMap + ); + } + if (NvmeController->AdminCompletionUnAligned) { + NvmeController->PciIO->FreeBuffer (NvmeController->PciIO, \ + EFI_SIZE_TO_PAGES(NvmeController->AdminCompletionUnAlignedSize), \ + (VOID *)NvmeController->AdminCompletionUnAligned + ); + } + + if (NvmeController->Queue1SubmissionQueueUnMap) { + NvmeController->PciIO->Unmap (NvmeController->PciIO, + NvmeController->Queue1SubmissionQueueUnMap + ); + } + if (NvmeController->Queue1SubmissionUnAligned) { + NvmeController->PciIO->FreeBuffer (NvmeController->PciIO, \ + EFI_SIZE_TO_PAGES(NvmeController->Queue1SubmissionUnAlignedSize), \ + (VOID *)NvmeController->Queue1SubmissionUnAligned + ); + } + + if (NvmeController->Queue1CompletionQueueUnMap) { + NvmeController->PciIO->Unmap (NvmeController->PciIO, + NvmeController->Queue1CompletionQueueUnMap + ); + } + if (NvmeController->Queue1CompletionUnAligned) { + NvmeController->PciIO->FreeBuffer (NvmeController->PciIO, \ + EFI_SIZE_TO_PAGES(NvmeController->Queue1CompletionUnAlignedSize), \ + (VOID *)NvmeController->Queue1CompletionUnAligned + ); + } + + if (NvmeController->NvmeCmdWrapper) { + pBS->FreePool (NvmeController->NvmeCmdWrapper); + } + + if (NvmeController) { + pBS->FreePool (NvmeController); + } + + } + + return EFI_SUCCESS; + +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: InitializeNvmeController +// +// Description: Initialize Nvme controller and ADMIN submission and Completion queues +// +// Input: +// IN EFI_HANDLE Controller, +// IN EFI_HANDLE DriverBindingHandle, +// OUT AMI_NVME_CONTROLLER_PROTOCOL **NvmeControllerReturnAddress +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +InitializeNvmeController( + IN EFI_HANDLE Controller, + IN EFI_HANDLE DriverBindingHandle, + OUT AMI_NVME_CONTROLLER_PROTOCOL **NvmeControllerReturnAddress +) +{ + + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIO; + PCI_TYPE00 PciConfig; + UINT64 ControllerCapabilities; + UINT32 Delay; + UINT32 ProgramCC = 0; + EFI_PHYSICAL_ADDRESS AdminQueueAddress = 0; + UINTN AllocatePageSize; + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController = NULL; + UINT64 PciAttributes; + + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof(AMI_NVME_CONTROLLER_PROTOCOL), + (VOID**)&NvmeController + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + *NvmeControllerReturnAddress = NvmeController; + + // Clear memory + pBS->SetMem(NvmeController, sizeof(AMI_NVME_CONTROLLER_PROTOCOL), 0); + + InitializeListHead (&NvmeController->ActiveNameSpaceList); + + // Get the PciIO interface + Status = pBS->OpenProtocol( Controller, + &gEfiPciIoProtocolGuid, + (VOID **)&PciIO, + DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (EFI_ERROR(Status)) { + return Status; + } + + // Enable PCI Cmd register + Status = PciIO->Attributes(PciIO, EfiPciIoAttributeOperationSupported, 0, &PciAttributes); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = PciIO->Attributes(PciIO, EfiPciIoAttributeOperationEnable, PciAttributes & EFI_PCI_DEVICE_ENABLE, NULL); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = PciIO->Pci.Read ( PciIO, + EfiPciIoWidthUint8, + 0, + sizeof (PCI_TYPE00), + &PciConfig + ); + + if (EFI_ERROR(Status)) { + return Status; + } + NvmeController->NvmeBarOffset = Shl64(PciConfig.Device.Bar[1], 32) + (PciConfig.Device.Bar[0] & ~(0x07)); + NvmeController->PciIO = PciIO; + NvmeController->ControllerHandle = Controller; + + ControllerCapabilities = Shl64(CONTROLLER_REG32(NvmeController->NvmeBarOffset, 4), 32) + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, 0); + + // Initialize various capability values + + NvmeController->RawControllerCapabilities = ControllerCapabilities; + NvmeController->MaxQueueEntrySupported = (ControllerCapabilities & 0xFFFF) + 1; + NvmeController->ContiguousQueueRequired = (BOOLEAN)(Shr64((ControllerCapabilities & 0x10000), 16)); + NvmeController->ArbitrationMechanismSupport = (BOOLEAN)(Shr64((ControllerCapabilities & 0x60000), 17)); + NvmeController->TimeOut = (UINT8)(Shr64((ControllerCapabilities & 0xFF000000), 24)); // 500msec units + NvmeController->DoorBellStride = (UINT8)(UINTN) (Shr64((ControllerCapabilities & 0xF00000000), 32)); + NvmeController->NVMResetSupport = (BOOLEAN) (Shr64((ControllerCapabilities & 0x1000000000), 36)); + NvmeController->CmdSetsSupported = (UINT8)(UINTN) (Shr64((ControllerCapabilities & 0x1FE000000000), 37)); + NvmeController->MemoryPageSizeMin = (UINT32)(UINTN) Shl64(1, (UINT8)(UINTN)(Shr64((ControllerCapabilities & 0xF000000000000), 48) + 12)); // In Bytes + NvmeController->MemoryPageSizeMax = (UINT32)(UINTN) Shl64(1, (UINT8)(UINTN)(Shr64((ControllerCapabilities & 0xF0000000000000), 52) + 12)); // In Bytes + + PrintNvmeCapability(NvmeController); + + // Is NVM command set supported + if (!(NvmeController->CmdSetsSupported & 0x1)) { + return EFI_UNSUPPORTED; + } + + // Check if the controller is already running. If yes stop it. + Delay = NvmeController->TimeOut * 500; + + // Check if the controller is still in shutdown process occuring state + do { + + if ((CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CSTS) & 0xC) != 4) { + break; + } + pBS->Stall(1000); // 1msec delay + + }while (--Delay); + + if (!Delay) { + return EFI_DEVICE_ERROR; + } + + Delay = NvmeController->TimeOut * 500; + if (CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CC) & 0x1) { + + // Disable Enable bit + CONTROLLER_REG32_AND (NvmeController->NvmeBarOffset, Offset_CC, ~0x01); + do { + if (!(CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CSTS) & 0x1)) { + break; + } + pBS->Stall(1000); // 1msec delay + }while (--Delay); + } + + if (!Delay) { + return EFI_DEVICE_ERROR; + } + + // Initialize Controller configuration register. + // Select Round Robin and NVM Command Set (both values are zero) + // Max Page Size + NvmeController->MemoryPageSize = NvmeController->MemoryPageSizeMin; + ProgramCC |= (UINT32) Shl64((UINTN)Shr64(NvmeController->MemoryPageSize, 13), 7); + + + // Initialize with default value. Later it can be modified + ProgramCC |= Shl64(6, 16); // I/O Submission Queue Entry Size + ProgramCC |= Shl64(4, 20); // I/O Completion Queue Entry Size + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CC) = ProgramCC; + + // Allocate memory for Admin Queue. Each entry is 64bytes long and queue should be aligned on MemoryPageSize + AllocatePageSize = NvmeController->MemoryPageSize + + ADMIN_QUEUE_SIZE * sizeof (NVME_ADMIN_COMMAND); + +#if Nvme_VERBOSE_PRINT + TRACE((-1, "Value programmed in Control register : %08X\n", ProgramCC)); +#endif + + Status = NvmeController->PciIO->AllocateBuffer (NvmeController->PciIO, + AllocateAnyPages, + EfiRuntimeServicesData, + EFI_SIZE_TO_PAGES(AllocatePageSize), + (VOID **)&(AdminQueueAddress), + EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + NvmeController->AdminSubmissionUnAligned = AdminQueueAddress; + NvmeController->AdminSubmissionUnAlignedSize = EFI_SIZE_TO_PAGES(AllocatePageSize); + NvmeController->AdminSubmissionQueue = (AdminQueueAddress & ~(NvmeController->MemoryPageSize - 1)) + + NvmeController->MemoryPageSize; + + Status = NvmeController->PciIO->Map ( NvmeController->PciIO, + EfiPciIoOperationBusMasterCommonBuffer, + (VOID *)NvmeController->AdminSubmissionQueue, + &AllocatePageSize, + &NvmeController->AdminSubmissionQueueMappedAddr, + &NvmeController->AdminSubmissionQueueUnMap + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + Status = NvmeController->PciIO->AllocateBuffer (NvmeController->PciIO, + AllocateAnyPages, + EfiRuntimeServicesData, + EFI_SIZE_TO_PAGES(AllocatePageSize), + (VOID **)&(AdminQueueAddress), + EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + NvmeController->AdminCompletionUnAligned = AdminQueueAddress; + NvmeController->AdminCompletionUnAlignedSize = EFI_SIZE_TO_PAGES(AllocatePageSize); + NvmeController->AdminCompletionQueue = (AdminQueueAddress & ~(NvmeController->MemoryPageSize - 1)) + + NvmeController->MemoryPageSize; + + Status = NvmeController->PciIO->Map ( NvmeController->PciIO, + EfiPciIoOperationBusMasterCommonBuffer, + (VOID *)NvmeController->AdminCompletionQueue, + &AllocatePageSize, + &NvmeController->AdminCompletionQueueMappedAddr, + &NvmeController->AdminCompletionQueueUnMap + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + NvmeController->AdminSubmissionQueueSize = ADMIN_QUEUE_SIZE; + NvmeController->AdminCompletionQueueSize = ADMIN_QUEUE_SIZE; + + // Clear memory + pBS->SetMem((VOID *)NvmeController->AdminSubmissionQueue, NvmeController->AdminSubmissionQueueSize, 0); + pBS->SetMem((VOID *)NvmeController->AdminCompletionQueue, NvmeController->AdminCompletionQueueSize, 0); + + // Program Admin Queue Size and Base Address + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Aqa) = + (UINT32)(Shl64((NvmeController->AdminCompletionQueueSize - 1),16) + + (NvmeController->AdminSubmissionQueueSize - 1)); + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Asq) = + (UINT32) NvmeController->AdminSubmissionQueueMappedAddr; + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Asq + 4) = + (UINT32)Shr64(NvmeController->AdminSubmissionQueueMappedAddr, 32); + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Acq) = + (UINT32)NvmeController->AdminCompletionQueueMappedAddr; + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Acq + 4) = + (UINT32)Shr64(NvmeController->AdminCompletionQueueMappedAddr, 32); + +#if NVME_VERBOSE_PRINT + TRACE ((-1, "Admin Submission Queue Size : %08X\n", NvmeController->AdminSubmissionQueueSize)); + TRACE ((-1, "Admin Completion Queue Size : %08X\n", NvmeController->AdminCompletionQueueSize)); + TRACE ((-1, "Admin Submission Queue Offset : %08X\n", NvmeController->AdminSubmissionQueue)); + TRACE ((-1, "Admin Completion Queue Offset : %08X\n", NvmeController->AdminCompletionQueue)); +#endif + + NvmeController->AdminPhaseTag = FALSE; + + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof(NVME_COMMAND_WRAPPER), + (VOID**)&(NvmeController->NvmeCmdWrapper) + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + // Enable Controller + CONTROLLER_REG32_OR(NvmeController->NvmeBarOffset, Offset_CC, 0x1); + + // Wait for the controller to get ready + // Check if the cobtroller is already running. If yes stop it. + Delay = NvmeController->TimeOut * 500; + do { + if ((CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CSTS) & 0x1)) { + break; + } + pBS->Stall(1000); // 1msec delay + } while (--Delay); + + if (!Delay) { + return EFI_DEVICE_ERROR; + } + + Status = SetNumberOfQueues (NvmeController); + if (EFI_ERROR(Status)) { + return Status; + } + + // Install NvmeController + Status = pBS->InstallMultipleProtocolInterfaces( + &Controller, + &gAmiNvmeControllerProtocolGuid, + NvmeController, + NULL + ); + + + return Status; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: GetIdentifyData +// +// Description: Issue Nvme Admin Identify cmd +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// OUT UINT8 *IdentifyData, +// IN UINT8 ControllerNameSpaceStructure, +// IN UINT32 NameSpaceID +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// ControllerNameSpaceStructure can take 0/1/2 : See Figure 81 NVM Express 1.1 Spec +// NameSpaceID can be 0 or specific NameSpace ID. See Figure 38 NVM Express 1.1 Spec +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +GetIdentifyData ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + OUT UINT8 *IdentifyData, + IN UINT8 ControllerNameSpaceStructure, + IN UINT32 NameSpaceID +) +{ + + EFI_STATUS Status; + NVME_COMMAND_WRAPPER *NvmeCmdWrapper = NULL; + COMPLETION_QUEUE_ENTRY CompletionData; + + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof(NVME_COMMAND_WRAPPER), + (VOID**)&(NvmeCmdWrapper) + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + // Clear memory + pBS->SetMem(NvmeCmdWrapper, sizeof(NVME_COMMAND_WRAPPER), 0); + + // Build NVME command + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = IDENTIFY; + NvmeCmdWrapper->NvmCmd.CMD0.FusedOperation = 0; + NvmeCmdWrapper->NvmCmd.CMD0.PSDT = 0; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeController->CommandIdentifierAdmin; + NvmeCmdWrapper->NvmCmd.NSID = NameSpaceID; + + NvmeCmdWrapper->NvmCmd.PRP1 = (UINT64)IdentifyData; + + // If PRP1 isn't aligned on MemoryPageSize, then PRP2 will also be used. + NvmeCmdWrapper->NvmCmd.PRP2 = ((UINT64)IdentifyData & ~((UINT64)NvmeController->MemoryPageSize-1)) + + NvmeController->MemoryPageSize; + + NvmeCmdWrapper->NvmCmd.CDW10 = ControllerNameSpaceStructure; + + NvmeCmdWrapper->AdminOrNVMCmdSet = TRUE; + NvmeCmdWrapper->SQIdentifier = 0; // Queue 0 for Admin cmds + NvmeCmdWrapper->CmdTimeOut = 1000; + + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, &CompletionData); + + if (!EFI_ERROR(Status)) { + PrintIdentifyDataStructure (IdentifyData, ControllerNameSpaceStructure); + } + + pBS->FreePool(NvmeCmdWrapper); + return Status; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: SetNumberOfQueues +// +// Description: Issue Set feature cmd to set the # if queues to 1 +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +SetNumberOfQueues ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +) +{ + + EFI_STATUS Status; + NVME_COMMAND_WRAPPER *NvmeCmdWrapper = NvmeController->NvmeCmdWrapper; + COMPLETION_QUEUE_ENTRY CompletionData; + + // Issue Set Feature cmd to initilaize # of queues to 1 + pBS->SetMem(NvmeController->NvmeCmdWrapper, sizeof(NVME_COMMAND_WRAPPER), 0); + + // Build NVME command + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = SET_FEATURES; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeController->CommandIdentifierAdmin; + + NvmeCmdWrapper->NvmCmd.CDW10 = 0x7; + NvmeCmdWrapper->NvmCmd.CDW11 = 0x10001; + + NvmeCmdWrapper->AdminOrNVMCmdSet = TRUE; + NvmeCmdWrapper->SQIdentifier = 0; // Queue 0 for Admin cmds + NvmeCmdWrapper->CmdTimeOut = 1000; + + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, &CompletionData); + + return Status; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: EnumerateActiveNameSpace +// +// Description: Detects active Namespavce and adds it into a linked list +// +// Input: +// IN OUT AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +EnumerateActiveNameSpace ( + IN OUT AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +) +{ + + EFI_STATUS Status; + ACTIVE_NAMESPACE_DATA *ActiveNameSpaceData = 0; + UINT32 i; + UINT32 Index; + UINT16 DeviceName[41]; + CHAR8 Language[] = LANGUAGE_CODE_ENGLISH; + EFI_UNICODE_STRING_TABLE *tempUnicodeTable; + + NvmeController->ActiveNameSpaceList.ForwardLink = &(NvmeController->ActiveNameSpaceList); + NvmeController->ActiveNameSpaceList.BackLink = &(NvmeController->ActiveNameSpaceList); + + // Get Identify NameSpace Data for each Namespace + for (i = 1; (i < 1024) && NvmeController->ActiveNameSpaceIDs[i]; i++){ + + // Get the list of Active Namespace IDs + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof (ACTIVE_NAMESPACE_DATA), + (VOID**)&ActiveNameSpaceData + ); + if (EFI_ERROR(Status)) { + return Status; + } + + pBS->SetMem(ActiveNameSpaceData, sizeof(ACTIVE_NAMESPACE_DATA), 0); + + ActiveNameSpaceData->Link.ForwardLink = &(ActiveNameSpaceData->Link); + ActiveNameSpaceData->Link.BackLink = &(ActiveNameSpaceData->Link); + + ActiveNameSpaceData->Signature = ACTIVE_NAME_SPACE_SIG; + ActiveNameSpaceData->NvmeController = NvmeController; + ActiveNameSpaceData->ActiveNameSpaceID = NvmeController->ActiveNameSpaceIDs[i]; + + Status = DetectActiveNameSpace (NvmeController, ActiveNameSpaceData); + + if (!EFI_ERROR(Status)) { + + TRACE((-1,"NameSpace %02X detected %lx\n", ActiveNameSpaceData->ActiveNameSpaceID, ActiveNameSpaceData)); + InsertTailList (&NvmeController->ActiveNameSpaceList, &ActiveNameSpaceData->Link); + + } else { + + pBS->FreePool(ActiveNameSpaceData); + // First instance of zero marks the end of valid namespace IDs + if (!NvmeController->ActiveNameSpaceIDs[i+1]) { + break; + } + continue; + } + + // + // Convert the Device string from Engligh to Unicode + // + ActiveNameSpaceData->UDeviceName = NULL; + + pBS->SetMem(DeviceName, sizeof(DeviceName), 0); + + for (Index = 0; Index < 40; Index ++) { + DeviceName[Index] = ((UINT8 *)NvmeController->IdentifyControllerData->ModelNumber)[Index]; + } + DeviceName[40] = 0; // Word + + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof (EFI_UNICODE_STRING_TABLE) * 2, + (VOID**)&tempUnicodeTable + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + pBS->SetMem(tempUnicodeTable, sizeof(EFI_UNICODE_STRING_TABLE) * 2, 0); + + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof (Language), + (VOID**)&tempUnicodeTable[0].Language + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + Status = pBS->AllocatePool (EfiBootServicesData, + sizeof (DeviceName), + (VOID**)&tempUnicodeTable[0].UnicodeString + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + pBS->CopyMem(tempUnicodeTable[0].Language, &Language, sizeof(Language)); + pBS->CopyMem(tempUnicodeTable[0].UnicodeString, DeviceName, sizeof (DeviceName)); + tempUnicodeTable[1].Language = NULL; + tempUnicodeTable[1].UnicodeString = NULL; + ActiveNameSpaceData->UDeviceName = tempUnicodeTable; + + // First instance of zero marks the end of valid namespace IDs + if (!NvmeController->ActiveNameSpaceIDs[i+1]) { + break; + } + } + + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: InstallBlockIoDiskInfo +// +// Description: Install BlockIo and DevicePath protocol for Active namespace +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +InstallBlockIoDiskInfo ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +) +{ + + EFI_STATUS Status = EFI_SUCCESS; + ACTIVE_NAMESPACE_DATA *ActiveNameSpace; + EFI_LIST_ENTRY *LinkData; + EFI_BLOCK_IO_MEDIA *BlkMedia; + EFI_PCI_IO_PROTOCOL *PciIO; + UINT32 BlockSize; + UINTN AllocatePageSize; + UINT8 *Buffer; + + for (LinkData = NvmeController->ActiveNameSpaceList.ForwardLink; + LinkData != &NvmeController->ActiveNameSpaceList; + LinkData = LinkData->ForwardLink) { + + ActiveNameSpace = _CR(LinkData ,ACTIVE_NAMESPACE_DATA, Link); + + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_BLOCK_IO_MEDIA), + (VOID**)&BlkMedia + ); + + if (EFI_ERROR(Status)) return Status; + + pBS->SetMem(BlkMedia, sizeof(EFI_BLOCK_IO_MEDIA), 0); + + // PRP2List will be cleared when used + AllocatePageSize = NvmeController->MemoryPageSize; + Status = NvmeController->PciIO->AllocateBuffer (NvmeController->PciIO, + AllocateAnyPages, + EfiRuntimeServicesData, + EFI_SIZE_TO_PAGES(AllocatePageSize), + (VOID**)&ActiveNameSpace->PRP2List, + EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + Status = NvmeController->PciIO->Map ( NvmeController->PciIO, + EfiPciIoOperationBusMasterCommonBuffer, + (VOID *)ActiveNameSpace->PRP2List, + &AllocatePageSize, + &ActiveNameSpace->PRP2ListMappedAddr, + &ActiveNameSpace->PRP2ListUnMap + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + + BlkMedia->MediaId = 0; + BlkMedia->RemovableMedia = FALSE; + BlkMedia->MediaPresent = TRUE; + BlkMedia->LogicalPartition = FALSE; + BlkMedia->ReadOnly = FALSE; + BlkMedia->WriteCaching = FALSE; + BlockSize = ActiveNameSpace->IdentifyNamespaceData.LBAF[ActiveNameSpace->IdentifyNamespaceData.FLBAS & 0xF].LBADS; + BlkMedia->BlockSize = (UINT32) Shl64(1, BlockSize); + BlkMedia->IoAlign = 2; // NvmeController->MemoryPageSize; + BlkMedia->LastBlock = (EFI_LBA) (ActiveNameSpace->IdentifyNamespaceData.NSIZE - 1); // Name space Size + BlkMedia->LowestAlignedLba = 0; + BlkMedia->LogicalBlocksPerPhysicalBlock = 1; + BlkMedia->OptimalTransferLengthGranularity = BlkMedia->BlockSize; + + ActiveNameSpace->NvmeBlockIO.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3; + ActiveNameSpace->NvmeBlockIO.Media = BlkMedia; + ActiveNameSpace->NvmeBlockIO.Reset = NvmeReset; + ActiveNameSpace->NvmeBlockIO.ReadBlocks = NvmeReadBlocks; + ActiveNameSpace->NvmeBlockIO.WriteBlocks = NvmeWriteBlocks; + ActiveNameSpace->NvmeBlockIO.FlushBlocks = NvmeFlushBlocks; + + // DiskInfo Protocol + pBS->CopyMem (&(ActiveNameSpace->NvmeDiskInfo.Interface), &gEfiDiskInfoNvmeInterfaceGuid, sizeof (EFI_GUID)); + + ActiveNameSpace->NvmeDiskInfo.Inquiry = NvmeDiskInfoInquiry; + ActiveNameSpace->NvmeDiskInfo.Identify = NvmeDiskInfoIdentify; + ActiveNameSpace->NvmeDiskInfo.SenseData = NvmeDiskInfoSenseData; + ActiveNameSpace->NvmeDiskInfo.WhichIde = NvmeDiskInfoWhichIde; + + // Create DevicePath Protocol + Status = CreateNvmeDevicePath (This, ActiveNameSpace); + if (EFI_ERROR(Status)) { + continue; + } + + // Install Devicepath and Block IO protocol + Status = pBS->InstallMultipleProtocolInterfaces ( + &(ActiveNameSpace->NvmeDeviceHandle), + &gEfiDevicePathProtocolGuid, ActiveNameSpace->EfiDevicePath, + &gEfiBlockIoProtocolGuid, &(ActiveNameSpace->NvmeBlockIO), + &gEfiDiskInfoProtocolGuid, &(ActiveNameSpace->NvmeDiskInfo), + NULL); + + if (EFI_ERROR(Status)) { + continue; + } + + // Open PCI IO protocol by CHILD + Status = pBS->OpenProtocol ( + NvmeController->ControllerHandle, + &gEfiPciIoProtocolGuid, + (VOID **)&PciIO, + This->DriverBindingHandle, + ActiveNameSpace->NvmeDeviceHandle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER); + + ASSERT_EFI_ERROR(Status); + + ActiveNameSpace->Configured = TRUE; + + // Check if the drive ready to return data + + Status = pBS->AllocatePages ( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES(ActiveNameSpace->NvmeBlockIO.Media->BlockSize), + (EFI_PHYSICAL_ADDRESS*)&(Buffer)); + + if (EFI_ERROR(Status)) { + return Status; + } + + + Status = ReadBlock (NvmeController, ActiveNameSpace, Buffer); + if (!EFI_ERROR(Status)) { + // No error check for Int13 installation + InstallNvmeLegacyDevice(NvmeController, ActiveNameSpace, Buffer); + } + + pBS->FreePages((EFI_PHYSICAL_ADDRESS)Buffer, EFI_SIZE_TO_PAGES(ActiveNameSpace->NvmeBlockIO.Media->BlockSize)); + } + +#if NvmeSmm_SUPPORT + if( gLegacyNvmeBuffer == NULL ) { + Status = pBS->AllocatePages ( + AllocateAnyPages, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES(ActiveNameSpace->NvmeBlockIO.Media->BlockSize), + (EFI_PHYSICAL_ADDRESS*)&(gLegacyNvmeBuffer )); + if (EFI_ERROR(Status)) { + ASSERT_EFI_ERROR(Status); + return Status; + } + } + NvmeController->LegacyNvmeBuffer=gLegacyNvmeBuffer; + + // Move the Controller and ActiveName Space data into SMM also. + // This will done for each controller in the system + TransferNvmeDataToSmram(NvmeController); +#endif + + return Status; +} + +#if NvmeSmm_SUPPORT + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: TransferNvmeDataToSmram +// +// Description: Transfer the Nvme Controller information to SMRAM area that would be used +// by the Nvme SMM driver +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +// +// Output: +// NONE +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +VOID +TransferNvmeDataToSmram ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +) +{ + + EFI_STATUS SmmStatus; + UINTN NvmeControllerAddress = 0; + static EFI_GUID gNvmeSmmGuid = NVME_SMM_GUID; + +#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014) + EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication; + EFI_SMM_COMMUNICATE_HEADER *CommHeader; + UINT8 CommBuffer[sizeof(EFI_GUID) + sizeof(UINTN) + sizeof(NvmeController)]; + UINTN CommSize = 0; + + // Get needed resource + SmmStatus = pBS->LocateProtocol ( + &gEfiSmmCommunicationProtocolGuid, + NULL, + (VOID **)&SmmCommunication + ); + + ASSERT_EFI_ERROR (SmmStatus); + + if (EFI_ERROR (SmmStatus)) { + return; + } + + CommHeader = (EFI_SMM_COMMUNICATE_HEADER *)&CommBuffer[0]; + pBS->CopyMem (&CommHeader->HeaderGuid, &gAmiSmmNvmeCommunicationGuid, sizeof(gAmiSmmNvmeCommunicationGuid)); + CommHeader->MessageLength = sizeof(NvmeController); + pBS->CopyMem (&(CommHeader->Data[0]), &NvmeController, sizeof(NvmeController)); + + // Send command + CommSize = sizeof(CommBuffer); + SmmStatus = SmmCommunication->Communicate ( + SmmCommunication, + &CommBuffer[0], + &CommSize + ); +#else + + NvmeControllerAddress = (UINT64)(NvmeController); + + // Save ComBuffer in NvmeSmmBuffer to use in SMM + SmmStatus = pRS->SetVariable ( L"NvmeSmmBuffer", + &gNvmeSmmGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(UINTN), + &NvmeControllerAddress); + + TRACE((-1, "CommHeader Data inNvmeBus = %x\n", NvmeControllerAddress)); + + IoWrite8 (SW_SMI_IO_ADDRESS, NVME_INIT_SMM_SWSMI); +#endif + + return; + +} +#endif + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: CreateNVMeDevicePath +// +// Description: Allocate memory and create a NVMe devicepath +// +// Input: +// IN EFI_DRIVER_BINDING_PROTOCOL *This, +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +CreateNvmeDevicePath ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN ACTIVE_NAMESPACE_DATA *ActiveNameSpace + ) +{ + + EFI_STATUS Status; + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController = ActiveNameSpace->NvmeController; + NVME_DEVICE_PATH NewDevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + NewDevicePath.Header.Type = MESSAGING_DEVICE_PATH; + NewDevicePath.Header.SubType = MSG_NVME_DP; + SetDevicePathNodeLength(&(NewDevicePath.Header), sizeof(NVME_DEVICE_PATH)); + NewDevicePath.Nsid = ActiveNameSpace->ActiveNameSpaceID; + NewDevicePath.EUI64 = ActiveNameSpace->IdentifyNamespaceData.EUI64; + + // + // Append the Device Path + // + Status = pBS->OpenProtocol ( + NvmeController->ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&TempDevicePath, + This->DriverBindingHandle, + NvmeController->ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + ActiveNameSpace->EfiDevicePath = DPAddNode(TempDevicePath, &NewDevicePath.Header); + + return Status; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: DetectActiveNameSpace +// +// Description: Issue GetIdentifyData cmd to get the list of active name space. +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpaceData +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +DetectActiveNameSpace ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpaceData +) +{ + + EFI_STATUS Status; + + // Get list of Active NameSpace Data + Status = GetIdentifyData (NvmeController, + (UINT8*)&(ActiveNameSpaceData->IdentifyNamespaceData), + 0, + ActiveNameSpaceData->ActiveNameSpaceID + ); + return Status; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: InstallNvmeLegacyDevice +// +// Description: Add the NVMe active partition as a legacy device +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpaceData +// IN UINT8 *Buffer +// +// Output: +// NONE +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** + +VOID +InstallNvmeLegacyDevice ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + IN UINT8 *Buffer +) +{ + + EFI_STATUS Status; + AMI_NVME_LEGACY_PROTOCOL *AmiNvmeLegacyProtocol = NULL; + NVME_LEGACY_MASS_DEVICE *NvmeLegacyMassDevice; + NVME_MASS_DEV_INFO *NvmeMassDevInfo; + CHAR8 *NewString; + UINTN PciSeg, PciBus, PciDev, PciFunc; + + + //If block size is not 512 do install INT13 + if (ActiveNameSpace->NvmeBlockIO.Media->BlockSize != 0x200) { + return; + } + + Status = pBS->LocateProtocol(&gAmiNvmeLegacyProtocolGuid, NULL, (VOID**)&AmiNvmeLegacyProtocol); + // Legacy Support disabled. + if(EFI_ERROR(Status) || AmiNvmeLegacyProtocol == NULL ) { + return; + } + + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof (NVME_LEGACY_MASS_DEVICE), + (VOID**)&NvmeLegacyMassDevice + ); + + if (EFI_ERROR(Status)){ + return; + } + + + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof (NVME_MASS_DEV_INFO), + (VOID**)&NvmeMassDevInfo + ); + + if (EFI_ERROR(Status)){ + pBS->FreePool (NvmeLegacyMassDevice); + return; + } + + Status = pBS->AllocatePool( + EfiBootServicesData, + 256, + (VOID *) &NewString); + ASSERT_EFI_ERROR (Status); + + // Read the first sector of the device + ActiveNameSpace->dMaxLBA = ActiveNameSpace->NvmeBlockIO.Media->LastBlock; + GetNvmeGeometryData(ActiveNameSpace, NvmeMassDevInfo, Buffer); + + NvmeMassDevInfo->wBlockSize=ActiveNameSpace->NvmeBlockIO.Media->BlockSize; + NvmeMassDevInfo->dMaxLba=ActiveNameSpace->dMaxLBA; + NvmeMassDevInfo->bHeads=ActiveNameSpace->NumHeads; + NvmeMassDevInfo->bSectors=ActiveNameSpace->NumSectors; + NvmeMassDevInfo->wCylinders=ActiveNameSpace->NumCylinders; + NvmeMassDevInfo->bNonLBAHeads=ActiveNameSpace->LBANumHeads; + NvmeMassDevInfo->bNonLBASectors=ActiveNameSpace->LBANumSectors; + NvmeMassDevInfo->wNonLBACylinders=ActiveNameSpace->LBANumCyls; + + PrintNvmeMassDevInfo (NvmeMassDevInfo); + + // Get the NVMe controller Bus,Dev and Fun + NvmeController->PciIO->GetLocation (NvmeController->PciIO, &PciSeg, &PciBus, &PciDev, &PciFunc); + UnicodeStrToAsciiStr (ActiveNameSpace->UDeviceName->UnicodeString, NewString); + + NvmeLegacyMassDevice->PciBDF=(UINT16)((PciBus << 8)+(PciDev << 3) + PciFunc); + NvmeLegacyMassDevice->DevString=NewString; + NvmeLegacyMassDevice->DevInfo=(VOID*)NvmeMassDevInfo; + ActiveNameSpace->Int13DeviceAddress = gInt13DeviceAddress; + NvmeLegacyMassDevice->LogicalAddress=ActiveNameSpace->Int13DeviceAddress; + gInt13DeviceAddress++; + NvmeLegacyMassDevice->StorageType = NVME_MASS_DEV_HDD; + NvmeLegacyMassDevice->Handle=ActiveNameSpace->NvmeDeviceHandle; + + AmiNvmeLegacyProtocol->AddNvmeLegacyDevice(NvmeLegacyMassDevice); + + return; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: GetNvmeGeometryData +// +// Description: Get drive geometry data for INT13 support +// +// Input: +// IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace, +// IN OUT NVME_MASS_DEV_INFO *NvmeMassDevInfo, +// IN UINT8 *Buffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +GetNvmeGeometryData ( + IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + IN OUT NVME_MASS_DEV_INFO *NvmeMassDevInfo, + IN UINT8 *Buffer +) +{ + + EFI_STATUS Status; + UINT8 *ActPartAddr; + UINT32 dHS; + + + ActiveNameSpace->bStorageType = NVME_MASS_DEV_HDD; + ActiveNameSpace->bEmuType = 0; + + ActiveNameSpace->bHiddenSectors = 0; + // + // Check for validity of Boot Record + // + if ( *(UINT16*)(Buffer + 0x1FE) != 0xAA55 ) { + NvmeSetDefaultGeometry(ActiveNameSpace); + return EFI_NOT_FOUND; + } + + // + // Check for validity of the partition table + // + if ( NvmeValidatePartitionTable( Buffer, ActiveNameSpace->dMaxLBA, &ActPartAddr) == EFI_SUCCESS ) { + + // + // Read boot sector, set the LBA number to boot record LBA number + // + dHS = *((UINT32*)(ActPartAddr + 8)); + ActiveNameSpace->bHiddenSectors = (UINT8)dHS; // Save hidden sector value + + Status = NvmeReadWriteBlocks (ActiveNameSpace, ActiveNameSpace->NvmeBlockIO.Media->MediaId, (EFI_LBA)dHS, 512, Buffer, NULL, NVME_READ); + + if ( EFI_ERROR(Status) ) { + return EFI_NOT_FOUND; + } + + if ( NvmeUpdateCHSFromBootRecord(ActiveNameSpace, Buffer) == EFI_SUCCESS) { + return EFI_SUCCESS; + } else { + NvmeSetDefaultGeometry(ActiveNameSpace); + ActiveNameSpace->bHiddenSectors = 0; // Reset hidden sector value + return EFI_SUCCESS; + } + } + + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeSetDefaultGeometry +// +// Description: This procedure sets the default geometry for mass storage devices +// +// Input: +// IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeSetDefaultGeometry ( + IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace +) +{ + ActiveNameSpace->NumHeads = 0xFF; + ActiveNameSpace->LBANumHeads = 0xFF; + ActiveNameSpace->NumSectors = 0x3F; + ActiveNameSpace->LBANumSectors = 0x3F; + + NvmeMassUpdateCylinderInfo(ActiveNameSpace); + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeMassUpdateCylinderInfo +// +// Description: This procedure updates cylinder parameter for device geometry. +// head and sector parameters are required before invoking this +// function. +// +// Input: +// IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace, +// +// Output: +// NONE +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +VOID +NvmeMassUpdateCylinderInfo ( + IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace +) +{ + UINT32 data = (UINT32)(Div64(ActiveNameSpace->dMaxLBA,(ActiveNameSpace->NumSectors * ActiveNameSpace->NumHeads), NULL)); + + if (data <= 1) data++; + if (data > 0x3FF) data = 0x3FF; // DOS workaround + + ActiveNameSpace->NumCylinders = (UINT16)data; + ActiveNameSpace->LBANumCyls = (UINT16)data; + return; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeValidatePartitionTable +// +// Description: This procedure checks whether the partition table is valid. +// +// Input: +// IN UINT8 *Buffer, +// IN UINT64 dMaxLBA, +// OUT UINT8 **ActPartAddr +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeValidatePartitionTable ( + IN UINT8 *Buffer, + IN UINT64 dMaxLBA, + OUT UINT8 **ActPartAddr +) +{ + + UINT8 *PartPtr; + UINT8 PartNo = 0; + UINT8 *ActPart = NULL; + UINT8 ValidEntryCount = 0; + + // + // Drive has a partition table, start from 1st bootable partition + // + PartPtr = Buffer + 0x1BE; + + for (; PartNo<4; PartNo++, PartPtr+=0x10 ) { + + if (*PartPtr & 0x7F ) { + return EFI_NOT_FOUND; //BootFlag should be 0x0 or 0x80 + } + // + // Check whether beginning LBA is reasonable + // + if (*(UINT32*)(PartPtr + 8) > dMaxLBA) { + return EFI_NOT_FOUND; + } + + ValidEntryCount++; // Update valid entry count + // + // Update active entry offset + // + if (!(*PartPtr & 0x80)) continue; + if (ActPart) continue; + ActPart = PartPtr; + } + + if (ValidEntryCount < 1) return EFI_NOT_FOUND; // At least one valid partition is found + // + // If no active partition table entry found use first entry + // + if (ActPart == NULL) ActPart = Buffer + 0x1BE; + + *ActPartAddr = ActPart; + + return EFI_SUCCESS; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeUpdateCHSFromBootRecord +// +// Description: This function parses the boot record and extract the CHS +// information of the formatted media from the boot record. +// This routine checks for DOS & NTFS formats only +// +// Input: +// IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace, +// IN UINT8* BootRecord +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: The amount of data that will get printed can be controlled +// using DEBUG_ERROR_LEVEL_MASK SDL token. Make sure +// PcdDebugPrintErrorLevel is properly cloned and set to +// PcdsPatchableInModule in the project. +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeUpdateCHSFromBootRecord ( + IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + IN UINT8* BootRecord +) +{ + UINT32 OemName; + UINT8 Heads; + UINT8 SecPerTrack; + UINT16 SecTimesHeads; + UINT16 TotalSect; + + if (*((UINT16*)(BootRecord + 0x1FE)) != 0xAA55) { + return EFI_NOT_FOUND; + } + + // + // Read succeeded so the drive is formatted + // Check for valid MSDOS/MSWIN/NTFS boot record + // + OemName = *(UINT32*)(BootRecord + 3); + + if ((OemName != 0x4F44534D) && // 'ODSM' for MSDO + (OemName != 0x4957534D) && // 'IWSM' for MSWI + (OemName != 0x5346544E)) { // 'SFTN' for NTFS + // + // Check for valid FAT,FAT16,FAT32 boot records + // + *(BootRecord + 0x36 + 3) = 0x20; // Ignore the 4th byte and fill it with space + if ((*(UINT32*)(BootRecord + 0x36) != 0x20544146) && // " TAF" for FATx + (*(UINT32*)(BootRecord + 0x52) != 0x33544146)) { // "3TAF" for FAT3 + // + // Boot Record is invalid. Return with error + // + return EFI_NOT_FOUND; + } + } + + Heads = *(BootRecord + 0x1A); // Number of heads + SecPerTrack = *(BootRecord + 0x18); // Sectors/track + SecTimesHeads = Heads * SecPerTrack; + + // Zero check added to prevent invalid sector/head information in BPB + if (SecTimesHeads == 0) { + return EFI_NOT_FOUND; + } + + TotalSect = *(UINT16*)(BootRecord + 0x13); + if ( TotalSect ) { + ActiveNameSpace->dMaxLBA = TotalSect; + } + + ActiveNameSpace->NumHeads = Heads; + ActiveNameSpace->LBANumHeads = Heads; + ActiveNameSpace->NumSectors = SecPerTrack; + ActiveNameSpace->LBANumSectors = SecPerTrack; + + + NvmeMassUpdateCylinderInfo(ActiveNameSpace); + + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: PrintIdentifyDataStructure +// +// Description: Prints Identify data structure +// +// Input: +// UINT8 *IdentifyData, +// UINT8 ControllerNameSpaceStructure +// +// Output: +// None +// +// Modified: +// +// Referrals: +// +//<AMI_PHDR_END> +//********************************************************************** +VOID +PrintIdentifyDataStructure ( + IN UINT8 *IdentifyData, + IN UINT8 ControllerNameSpaceStructure +) +{ + + +#if NVME_VERBOSE_PRINT + + IDENTIFY_CONTROLLER_DATA *IdentifyControllerData = (IDENTIFY_CONTROLLER_DATA *)IdentifyData; + IDENTIFY_NAMESPACE_DATA *IdentifyNameSpaceData = (IDENTIFY_NAMESPACE_DATA *)IdentifyData; + UINT32 *ActiveNameSapceID = (UINT32 *)IdentifyData; + UINT32 i; + UINT64 FirmwareVersion; + + switch (ControllerNameSpaceStructure){ + + case 1: + + FirmwareVersion = *(UINT64 *)(IdentifyControllerData->FirmwareRevision); + TRACE((-1,"\nIdentify Controller Data Structure\n")); + TRACE((-1, "Vendor ID : %08X\n", IdentifyControllerData->VID)); + TRACE((-1, "SubSystem Vendor ID : %08X\n", IdentifyControllerData->SSVID)); + TRACE((-1, "Firmware Version : %16lX\n", FirmwareVersion)); + TRACE((-1, "NameSpace Sharing Capability : %08X\n", IdentifyControllerData->CMIC)); + TRACE((-1, "Max. Data Transfer Size : %08X\n", IdentifyControllerData->MDTS)); + TRACE((-1, "Controller ID : %08X\n", IdentifyControllerData->ControllerID)); + TRACE((-1, "Optional Admin Cmd Support : %08X\n", IdentifyControllerData->OACS)); + TRACE((-1, "Abort Command Limit : %08X\n", IdentifyControllerData->ACL)); + TRACE((-1, "Asyn. Event Request Limit : %08X\n", IdentifyControllerData->AERL)); + TRACE((-1, "Firmware Updates : %08X\n", IdentifyControllerData->FRMW)); + TRACE((-1, "Log Page Attribute : %08X\n", IdentifyControllerData->LPA)); + TRACE((-1, "# of Power state supported : %08X\n", IdentifyControllerData->NPSS)); + TRACE((-1, "Admin Vendor Specific cmd : %08X\n", IdentifyControllerData->AVSCC)); + TRACE((-1, "Autonomous Power state attrib : %08X\n", IdentifyControllerData->APSTA)); + TRACE((-1, "Submission queue Entry Size : %08X\n", IdentifyControllerData->SQES)); + TRACE((-1, "Completion queue Entry Size : %08X\n", IdentifyControllerData->CQES)); + TRACE((-1, "Number of NameSpace : %08X\n", IdentifyControllerData->NN)); + TRACE((-1, "Optional NVM Command Support : %08X\n", IdentifyControllerData->ONCS)); + TRACE((-1, "Fused Operation Support : %08X\n", IdentifyControllerData->FUSES)); + TRACE((-1, "Format NVM Attribute : %08X\n", IdentifyControllerData->FNA)); + TRACE((-1, "Volatile Write Cache : %08X\n", IdentifyControllerData->VWC)); + TRACE((-1, "Atomic Write Unit Normal : %08X\n", IdentifyControllerData->AWUN)); + TRACE((-1, "Atomic Write Unit Power Fail : %08X\n", IdentifyControllerData->AWUPF)); + TRACE((-1, "NVM VS CMD Config : %08X\n", IdentifyControllerData->NVSCC)); + TRACE((-1, "Atomic Compare & Write Unit : %08X\n", IdentifyControllerData->ACWU)); + TRACE((-1, "SGL Support : %08X\n", IdentifyControllerData->SGLS)); + break; + + case 0: + TRACE((-1, "\nIdentify NameSpace Data Structure\n")); + TRACE((-1, "NameSpace Size : %08X\n", IdentifyNameSpaceData->NSIZE)); + TRACE((-1, "NameSpace Capacity : %08X\n", IdentifyNameSpaceData->NCAP)); + TRACE((-1, "NameSpace Utilization : %08X\n", IdentifyNameSpaceData->NUSE)); + TRACE((-1, "NameSpace Features : %08X\n", IdentifyNameSpaceData->NSFEAT)); + TRACE((-1, "No. of LBA Formats (0 Based) : %08X\n", IdentifyNameSpaceData->NLBAF)); + TRACE((-1, "Formatted LBA Size : %08X\n", IdentifyNameSpaceData->FLBAS)); + TRACE((-1, "Metadata Capabilities : %08X\n", IdentifyNameSpaceData->MC)); + TRACE((-1, "End-to-end data Protection cap : %08X\n", IdentifyNameSpaceData->DPC)); + TRACE((-1, "End-to-end data Protection settings : %08X\n", IdentifyNameSpaceData->DPS)); + TRACE((-1, "NameSpace Sharing : %08X\n", IdentifyNameSpaceData->NMIC)); + TRACE((-1, "Reservation Capabilites : %08X\n", IdentifyNameSpaceData->RESCAP)); + TRACE((-1, "IEEE Extended Unique Identifier : %016lx\n", IdentifyNameSpaceData->EUI64)); + for (i=0; i<16; i++){ + TRACE((-1, "LBA Format %02X Support : %08X\n", i, *(UINT32 *)&(IdentifyNameSpaceData->LBAF[i]))); + } + break; + + case 2: + TRACE((-1,"\nActive NameSpace IDs\n")); + for (i=0; i<1024 && ActiveNameSapceID[i]; i++){ + TRACE((-1, " %08X\n", i, ActiveNameSapceID[i])); + } + + } +#endif +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: PrintNvmeCapability +// +// Description: Prints Controller capabilities +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +// +// Output: +// None +// +// Modified: +// +// Referrals: +// +// Notes: The amount of data that will get printed can be controlled using DEBUG_ERROR_LEVEL_MASK SDL token. +// Make sure PcdDebugPrintErrorLevel is properly cloned and set to PcdsPatchableInModule in the project. +// +//<AMI_PHDR_END> +//********************************************************************** +VOID +PrintNvmeCapability ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +) +{ + +#if NVME_VERBOSE_PRINT + TRACE ((-1, "Controller Capabilitites Reg Value : %16lx\n", NvmeController->RawControllerCapabilities)); + TRACE ((-1, "Max. Queue Entrys Supported : %08X\n", NvmeController->MaxQueueEntrySupported)); + TRACE ((-1, "Contiguous Queue Required : %08X\n", NvmeController->ContiguousQueueRequired)); + TRACE ((-1, "Arbitration Mode Supported : %08X\n", NvmeController->ArbitrationMechanismSupport)); + TRACE ((-1, "TimeOut in 500msec unit : %08X\n", NvmeController->TimeOut)); + TRACE ((-1, "Doorbell Stride : %08X\n", NvmeController->DoorBellStride)); + TRACE ((-1, "NVM Subsystem Reset Support : %08X\n", NvmeController->NVMResetSupport)); + TRACE ((-1, "Command Sets Supported : %08X\n", NvmeController->CmdSetsSupported)); + TRACE ((-1, "Memory Page Size Min.in Bytes : %08X\n", NvmeController->MemoryPageSizeMin)); + TRACE ((-1, "Memory Page Size Max.in Bytes : %08X\n", NvmeController->MemoryPageSizeMax)); +#endif + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: ReadBlock +// +// Description: Read the Data from device +// +// Input: +// AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// ACTIVE_NAMESPACE_DATA *ActiveNameSpace +// +// Output: +// None +// +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +ReadBlock ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + OUT UINT8 *Buffer + +) +{ + + EFI_STATUS Status; + NVME_COMMAND_WRAPPER *NvmeCmdWrapper = NvmeController->NvmeCmdWrapper; + COMPLETION_QUEUE_ENTRY CompletionData; + UINT64 DataAddress = (UINTN)Buffer; + UINT32 LBANumber = 0; + UINT32 Retries = 0x800; + + do { + + // Clear memory + pBS->SetMem(NvmeCmdWrapper, sizeof(NVME_COMMAND_WRAPPER), 0); + + // Build NVME command + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = NVME_READ; + NvmeCmdWrapper->NvmCmd.CMD0.FusedOperation = 0; + NvmeCmdWrapper->NvmCmd.CMD0.PSDT = 0; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeController->CommandIdentifierQueue1; + NvmeCmdWrapper->NvmCmd.NSID = 1; + + NvmeCmdWrapper->NvmCmd.MPTR = 0; + NvmeCmdWrapper->NvmCmd.PRP1 = DataAddress; + NvmeCmdWrapper->NvmCmd.PRP2 = 0; + NvmeCmdWrapper->NvmCmd.CDW10 = LBANumber; // LBA 0 + NvmeCmdWrapper->NvmCmd.CDW11 = 0; + NvmeCmdWrapper->NvmCmd.CDW12 = 0x80000000; + NvmeCmdWrapper->NvmCmd.CDW13 = 0; + NvmeCmdWrapper->NvmCmd.CDW14 = 0; + + NvmeCmdWrapper->AdminOrNVMCmdSet = FALSE; + NvmeCmdWrapper->SQIdentifier = 1; // Cmd issued in Queue0 + NvmeCmdWrapper->CmdTimeOut = 1000; + + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, &CompletionData); + + } while (Retries-- && Status != EFI_SUCCESS); + + return Status; +} +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeReadBlocks +// +// Description: Reads data from the given LBA address +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// +// Output: +// None +// +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +NvmeReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer +) +{ + + ACTIVE_NAMESPACE_DATA *ActiveNameSpace = ACTIVE_NAMESPACE_DATA_FROM_THIS(This); + + return NvmeReadWriteBlocks (ActiveNameSpace, MediaId, LBA, BufferSize, Buffer, NULL, NVME_READ); + +} +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeWriteBlocks +// +// Description: Write data from the given LBA address +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +NvmeWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer +) +{ + + ACTIVE_NAMESPACE_DATA *ActiveNameSpace = ACTIVE_NAMESPACE_DATA_FROM_THIS(This); + + return NvmeReadWriteBlocks (ActiveNameSpace, MediaId, LBA, BufferSize, Buffer, NULL, NVME_WRITE); + +} +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeReset +// +// Description: Resets Nvme Controller +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This, +// IN BOOLEAN ExtendedVerification +// +// Output: +// None +// +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +NvmeReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification +) +{ + + EFI_STATUS Status = EFI_SUCCESS; + + return Status; +} +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeFlushBlocks +// +// Description: Flushes the data +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +NvmeFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This +) +{ + + EFI_STATUS Status; + ACTIVE_NAMESPACE_DATA *ActiveNameSpace = ACTIVE_NAMESPACE_DATA_FROM_THIS(This); + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController = ActiveNameSpace->NvmeController; + NVME_COMMAND_WRAPPER *NvmeCmdWrapper = NvmeController->NvmeCmdWrapper; + COMPLETION_QUEUE_ENTRY CompletionData; + + TRACE((-1,"NvmeFlushBlocks \n")); + + pBS->SetMem(NvmeCmdWrapper, sizeof(NVME_COMMAND_WRAPPER), 0); + + // Build NVME command + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = NVME_FLUSH; + NvmeCmdWrapper->NvmCmd.CMD0.FusedOperation = 0; + NvmeCmdWrapper->NvmCmd.CMD0.PSDT = 0; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeController->CommandIdentifierQueue1; + NvmeCmdWrapper->NvmCmd.NSID = ActiveNameSpace->ActiveNameSpaceID; + + NvmeCmdWrapper->AdminOrNVMCmdSet = FALSE; + NvmeCmdWrapper->SQIdentifier = NvmeController->NVMQueueNumber; + NvmeCmdWrapper->CmdTimeOut = 1000; // 1secs + + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, &CompletionData); + + TRACE((-1,"NvmeFlushBlocks Status %r \n", Status)); + + return Status; + +} +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeDiskInfoInquiry +// +// Description: Return Nvme device Inquiry data +// +// Input: +// IN EFI_DISK_INFO_PROTOCOL *This +// IN VOID *InquiryData, +// IN UINT32 *InquiryDataSize +// Output: +// EFI_STATUS /EFI_NOT_FOUND +// +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +NvmeDiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *InquiryDataSize +) +{ + + return EFI_NOT_FOUND; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeDiskInfoIdentify +// +// Description: Return Identify Data +// +// Input: +// IN EFI_DISK_INFO_PROTOCOL *This +// IN VOID *IdentifyData, +// IN UINT32 *IdentifyDataSize +// Output: +// EFI_STATUS +// Note: +// Return the Nvme device Identify command data. +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +NvmeDiskInfoIdentify ( + EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize +) +{ + ACTIVE_NAMESPACE_DATA *ActiveNameSpace = ACTIVE_NAMESPACE_DATA_FROM_THIS_FOR_DISKINFO(This); + + if (*IdentifyDataSize < sizeof (IDENTIFY_NAMESPACE_DATA)) { + *IdentifyDataSize = sizeof (IDENTIFY_NAMESPACE_DATA); + return EFI_BUFFER_TOO_SMALL; + } + + pBS->CopyMem (IdentifyData, &(ActiveNameSpace->IdentifyNamespaceData), sizeof (IDENTIFY_NAMESPACE_DATA)); + *IdentifyDataSize = sizeof (IDENTIFY_NAMESPACE_DATA); + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeDiskInfoSenseData +// +// Description: Return InfoSenseData. +// +// Input: +// IN EFI_DISK_INFO_PROTOCOL *This +// IN VOID *SenseData, +// IN UINT32 *SenseDataSize +// IN UINT8 *SenseDataNumber +// Output: +// EFI_STATUS / EFI_NOT_FOUND +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +NvmeDiskInfoSenseData ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT VOID *SenseData, + OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber +) +{ + return EFI_NOT_FOUND; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeDiskInfoWhichIde +// +// Description: Returns info about where the device is connected. +// +// Input: +// IN EFI_DISK_INFO_PROTOCOL *This +// IN UINT32 *IdeChannel +// IN UINT32 *IdeDevice +// Output: +// EFI_STATUS +// Note: +// Return Port and PMPort +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +NvmeDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice +) +{ + + ACTIVE_NAMESPACE_DATA *ActiveNameSpace = ACTIVE_NAMESPACE_DATA_FROM_THIS_FOR_DISKINFO(This); + + *IdeChannel = ActiveNameSpace->ActiveNameSpaceID; + *IdeDevice = 0; + return EFI_SUCCESS; +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: PrintNvmeMassDevInfo +// +// Description: Prints Nvme Mass Device Information +// +// Input: +// NVME_MASS_DEV_INFO *NvmeMassDevInfo +// +// Output: +// None +// +// Modified: +// +// Referrals: +// +// +//<AMI_PHDR_END> +//********************************************************************** +VOID +PrintNvmeMassDevInfo ( + NVME_MASS_DEV_INFO *NvmeMassDevInfo +) +{ + +#if NVME_VERBOSE_PRINT + TRACE((-1,"********** NvmeMassDevInfo **********\n")); + TRACE((-1, "wBlockSize : %08X\n", NvmeMassDevInfo->wBlockSize)); + TRACE((-1, "dMaxLba : %lX\n", NvmeMassDevInfo->dMaxLba)); + TRACE((-1, "bHeads : %08X\n", NvmeMassDevInfo->bHeads)); + TRACE((-1, "bSectors : %08X\n", NvmeMassDevInfo->bSectors)); + TRACE((-1, "wCylinders : %08X\n", NvmeMassDevInfo->wCylinders)); + TRACE((-1, "bNonLBAHeads : %08X\n", NvmeMassDevInfo->bNonLBAHeads)); + TRACE((-1, "bNonLBASectors : %08X\n", NvmeMassDevInfo->bNonLBASectors)); + TRACE((-1, "wNonLBACylinders : %08X\n", NvmeMassDevInfo->wNonLBACylinders)); +#endif + +} + + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeBus.h b/Core/EM/Nvme/NvmeBus.h new file mode 100644 index 0000000..9e4af09 --- /dev/null +++ b/Core/EM/Nvme/NvmeBus.h @@ -0,0 +1,539 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeBus.h 5 5/18/15 2:50a Karthikar $ +// +// $Revision: 5 $ +// +// $Date: 5/18/15 2:50a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeBus.h $ +// +// 5 5/18/15 2:50a Karthikar +// [TAG] EIP216763 +// [Category] Improvement +// [Description] Update the Aptio 4.x Nvme driver to Aptio 5.x Nvme +// driver Label 05 +// [Files] [Files] Nvme.mak,NvmeBus.c, NvmeBus.h, NvmeController.c, +// NvmePassthru.c,NvmePassthru.h, NvmeSmm.c, NvmExpressPassThru.h. +// +// 4 5/14/15 2:38a Karthikar +// +// 3 9/23/14 2:29a 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 +// +// +// +// +// +// +// +// 2 9/04/14 7:35a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// [Files] +// Nvme.cif +// Nvme.mak +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// [NvmeControllerLib] +// [NvmeSmm] +// [NVMEINT13] +// [NvmeProtocol] +// +// 1 6/20/14 6:27a Anandakrishnanl +// [TAG] EIP172958 +// [Category] New Feature +// [Description] Nvme Driver Intial Checkin +// [Files] Nvme.cif +// Nvme.sdl +// Nvme.mak +// Nvme.sd +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeController.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// NvmeController.h +// +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeBus.h +// +// Description: Header file for the Nvme Bus Driver +// +//<AMI_FHDR_END> +//********************************************************************** + +#ifndef _NVME_BUS_H_ +#define _NVME_BUS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "NvmeController.h" +#include "NvmeIncludes.h" +#include <Protocol/pDiskInfo.h> +#include <Protocol/AmiNvmeController.h> +#include <Protocol/AmiNvmePassThru.h> + +#define ADMIN_QUEUE_SIZE 0x100 +#define QUEUE1_SIZE 0x100 + +#define EFI_SIGNATURE_16( A, B ) ( (A) | (B << 8) ) +#define EFI_SIGNATURE_32( A, B, C, D ) ( EFI_SIGNATURE_16( A, B ) | (EFI_SIGNATURE_16( C, D ) << 16)) + +#define ACTIVE_NAME_SPACE_SIG EFI_SIGNATURE_32('N','V','M','E') + +#define PCI_CLASS_MASS_STORAGE 0x01 +#define PCI_CLASS_MASS_STORAGE_SOLID_STATE 0x08 +#define PCI_IF_MASS_STORAGE_SOLID_STATE 0x00 +#define PCI_IF_MASS_STORAGE_SOLID_STATE_NVMHCI 0x01 +#define PCI_IF_MASS_STORAGE_SOLID_STATE_ENTERPRISE_NVMHCI 0x02 + +#define IS_CLASS1(_p, c) ((_p)->Hdr.ClassCode[2] == (c)) +#define IS_CLASS2(_p, c, s) (IS_CLASS1 (_p, c) && ((_p)->Hdr.ClassCode[1] == (s))) +#define IS_CLASS3(_p, c, s, p) (IS_CLASS2 (_p, c, s) && ((_p)->Hdr.ClassCode[0] == (p))) + +#ifndef CR +#define CR(record, TYPE, field, signature) _CR(record, TYPE, field) +#endif + +#ifndef _CR +#define _CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) +#endif + +#define SetDevicePathNodeLength(a,l) { \ + (a)->Length[0] = (UINT8) (l); \ + (a)->Length[1] = (UINT8) ((l) >> 8); \ + } + +#define EFI_DISK_INFO_NVME_INTERFACE_GUID { 0x3ab14680, 0x5d3f, 0x4a4d, 0xbc, 0xdc, 0xcc, 0x38, 0x0, 0x18, 0xc7, 0xf7 } +#define NVME_SMM_GUID {0x1b30f467, 0xbf8b, 0x43b0, 0x81, 0x62, 0x29, 0xa, 0x27, 0xfd, 0x10, 0xcc} + +typedef struct { + CHAR8 *Language; + CHAR16 *UnicodeString; +} EFI_UNICODE_STRING_TABLE; + +typedef struct { + UINT16 VendorId; + UINT16 DeviceId; + UINT16 Command; + UINT16 Status; + UINT8 RevisionID; + UINT8 ClassCode[3]; + UINT8 CacheLineSize; + UINT8 LatencyTimer; + UINT8 HeaderType; + UINT8 BIST; +} PCI_DEVICE_INDEPENDENT_REGION; + +typedef struct { + UINT32 Bar[6]; + UINT32 CISPtr; + UINT16 SubsystemVendorID; + UINT16 SubsystemID; + UINT32 ExpansionRomBar; + UINT8 CapabilityPtr; + UINT8 Reserved1[3]; + UINT32 Reserved2; + UINT8 InterruptLine; + UINT8 InterruptPin; + UINT8 MinGnt; + UINT8 MaxLat; +} PCI_DEVICE_HEADER_TYPE_REGION; + +typedef struct { + PCI_DEVICE_INDEPENDENT_REGION Hdr; + PCI_DEVICE_HEADER_TYPE_REGION Device; +} PCI_TYPE00; + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL Header; + UINT32 Nsid; + UINT64 EUI64; +} NVME_DEVICE_PATH; + + +typedef struct { + UINT32 Signature; + EFI_HANDLE NvmeDeviceHandle; + BOOLEAN Configured; // Updated after installing BLOCK_IO_PROTOCOL + UINT32 ActiveNameSpaceID; + + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController; + + UINT64 *PRP2List; // if the data transfer size is more than twice the max. page size + EFI_PHYSICAL_ADDRESS PRP2ListMappedAddr; + VOID *PRP2ListUnMap; // if the data transfer size is more than twice the max. page size + // then PRP List is used. + IDENTIFY_NAMESPACE_DATA IdentifyNamespaceData; + + EFI_BLOCK_IO_PROTOCOL NvmeBlockIO; + EFI_DISK_INFO_PROTOCOL NvmeDiskInfo; + EFI_DEVICE_PATH_PROTOCOL *EfiDevicePath; + EFI_UNICODE_STRING_TABLE *UDeviceName; + UINT8 Int13DeviceAddress; // Used only for legacy Support + UINT16 wEmulationOption; // For INT13 support + UINT8 bHiddenSectors; + UINT8 NumHeads; + UINT8 LBANumHeads; + UINT16 NumCylinders; + UINT16 LBANumCyls; + UINT8 NumSectors; + UINT8 LBANumSectors; + UINT64 dMaxLBA; + UINT16 wBlockSize; + UINT8 bStorageType; + UINT8 bEmuType; + UINT8 PNM[27]; + UINT8 NvmeManufactureId[NVME_MANUFACTUREID_LENGTH]; + + EFI_LIST_ENTRY Link; // Links to parent NVM Controller + +} ACTIVE_NAMESPACE_DATA; + +#define ACTIVE_NAMESPACE_DATA_FROM_THIS(a) \ + CR(a, ACTIVE_NAMESPACE_DATA, NvmeBlockIO, ACTIVE_NAME_SPACE_SIG) + +#define ACTIVE_NAMESPACE_DATA_FROM_THIS_FOR_DISKINFO(a) \ + CR(a, ACTIVE_NAMESPACE_DATA, NvmeDiskInfo, ACTIVE_NAME_SPACE_SIG) + +typedef struct _NVME_MASS_DEV_INFO NVME_MASS_DEV_INFO; + +EFI_STATUS +NvmeBusSupported( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +); + +EFI_STATUS +NvmeBusStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath +); + +EFI_STATUS +NvmeBusStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer +); + +EFI_STATUS +InitializeNvmeController( + IN EFI_HANDLE Controller, + IN EFI_HANDLE DriverBindingHandle, + OUT AMI_NVME_CONTROLLER_PROTOCOL **NvmeController +); + +EFI_STATUS +InstallBlockIoDiskInfo ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +); + +EFI_STATUS +CreateAdditionalSubmissionCompletionQueue ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, + IN UINT16 QueueNumber, + IN UINT32 QueueSize +); + +EFI_STATUS +ExecuteNvmeCmd ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, + OUT COMPLETION_QUEUE_ENTRY *CmdCompletionData +); + +EFI_STATUS +GetIdentifyData ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + OUT UINT8 *IdentifyData, + IN UINT8 ControllerNameSpaceStructure, + IN UINT32 NameSpaceID +); + +VOID +PrintNvmeCapability ( + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +); + + +VOID +PrintNvmeMassDevInfo ( + NVME_MASS_DEV_INFO *NvmeMassDevInfo +); + +EFI_STATUS +AddToAdminSubmissionQueue ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper +); + +EFI_STATUS +AddToQueue1SubmissionQueue ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper +); + + +EFI_STATUS +UpdateDoorBellRegister ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN UINT16 QueueNumber, + IN UINT32 Value +); + +EFI_STATUS +WaitForCompletionQueueUpdate ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, + OUT COMPLETION_QUEUE_ENTRY *CmdCompletionData +); + +EFI_STATUS +SetNumberOfQueues ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +); + +EFI_STATUS +EnumerateActiveNameSpace ( + IN OUT AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +); + +EFI_STATUS +DetectActiveNameSpace ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpaceData +); + + +VOID +PrintIdentifyDataStructure ( + IN UINT8 *IdentifyData, + IN UINT8 ControllerNameSpaceStructure +); + +VOID +PrintCommandCompletionData ( + IN COMPLETION_QUEUE_ENTRY *pCmdCompletionData +); + +VOID +PrintNvmeCmdWrapper( + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper +); + +EFI_STATUS +ReadBlock ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + OUT UINT8 *Buffer +); + +EFI_STATUS +CreateNvmeDevicePath ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN ACTIVE_NAMESPACE_DATA *ActiveNameSpaceData +); + +EFI_STATUS +RecreateQueue1 ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +); + +EFI_STATUS +RecreateAllQueues ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +); + +EFI_STATUS +NvmeReadBlocks( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer +); + +EFI_STATUS +NvmeWriteBlocks( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer +); + +EFI_STATUS +NvmeReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification +); + +EFI_STATUS +NvmeFlushBlocks( + IN EFI_BLOCK_IO_PROTOCOL *This +); + +EFI_STATUS +ProgramPRP2List ( + IN UINT64 *PRP2List, + IN UINT32 PageSize, + IN UINTN BufferAddress, + IN UINTN BufferSize, + IN UINTN *PRP2TransferSize +); + +EFI_STATUS +NvmeReadWriteBlocks( + IN ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer, + OUT COMPLETION_QUEUE_ENTRY *NvmeCompletionData, + IN UINT8 ReadWriteOpCode +); + +EFI_STATUS +ExperimentWithAsyncEvents ( + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +); + +VOID +InstallNvmeLegacyDevice ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + IN UINT8 *Buffer +); + +EFI_STATUS +NvmeSetDefaultGeometry ( + IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace +); + +VOID +NvmeMassUpdateCylinderInfo ( + IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace +); + +EFI_STATUS +NvmeValidatePartitionTable ( + IN UINT8 *Buffer, + IN UINT64 dMaxLBA, + OUT UINT8 **ActPartAddr +); + +EFI_STATUS +NvmeUpdateCHSFromBootRecord ( + IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + IN UINT8* BootRecord +); + +EFI_STATUS +GetNvmeGeometryData ( + IN OUT ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + IN OUT NVME_MASS_DEV_INFO *NvmeMassDevInfo, + IN UINT8 *Buffer +); + +VOID +TransferNvmeDataToSmram ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +); + +EFI_STATUS +NvmeDiskInfoWhichIde ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT UINT32 *IdeChannel, + OUT UINT32 *IdeDevice +); + +EFI_STATUS +NvmeDiskInfoSenseData ( + IN EFI_DISK_INFO_PROTOCOL *This, + OUT VOID *SenseData, + OUT UINT32 *SenseDataSize, + OUT UINT8 *SenseDataNumber +); + +EFI_STATUS +NvmeDiskInfoIdentify ( + EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *IdentifyData, + IN OUT UINT32 *IdentifyDataSize +); + +EFI_STATUS +NvmeDiskInfoInquiry ( + IN EFI_DISK_INFO_PROTOCOL *This, + IN OUT VOID *InquiryData, + IN OUT UINT32 *InquiryDataSize +); + + +extern EFI_GUID gEfiSmmCommunicationProtocolGuid; +extern EFI_GUID gAmiSmmNvmeCommunicationGuid; + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif + +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeComponentName.c b/Core/EM/Nvme/NvmeComponentName.c new file mode 100644 index 0000000..b75ea5d --- /dev/null +++ b/Core/EM/Nvme/NvmeComponentName.c @@ -0,0 +1,270 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeComponentName.c 2 9/04/14 7:36a Anandakrishnanl $ +// +// $Revision: 2 $ +// +// $Date: 9/04/14 7:36a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeComponentName.c $ +// +// 2 9/04/14 7:36a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// [Files] +// Nvme.cif +// Nvme.mak +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// [NvmeControllerLib] +// [NvmeSmm] +// [NVMEINT13] +// [NvmeProtocol] +// +// 1 6/20/14 6:27a Anandakrishnanl +// [TAG] EIP172958 +// [Category] New Feature +// [Description] Nvme Driver Intial Checkin +// [Files] Nvme.cif +// Nvme.sdl +// Nvme.mak +// Nvme.sd +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeController.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// NvmeController.h +// +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeComonentName.c +// +// Description: Provides Controller and device Name information +// +//<AMI_FHDR_END> +//********************************************************************** + +#include "NvmeIncludes.h" +#include "NvmeBus.h" +#include <AmiLib.h> +#include <AmiDxeLib.h> + +extern EFI_DRIVER_BINDING_PROTOCOL gNvmeBusDriverBinding; +static EFI_GUID gAmiNvmeControllerProtocolGuid = AMI_NVME_CONTROLLER_PROTOCOL_GUID; + +EFI_STATUS +NvmeBusCtlDriverName( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName +); + +EFI_STATUS +NvmeBusCtlGetControllerName( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName +); + + +CHAR16 *gNvmeBusDriverName = L"AMI NVMe BUS Driver"; +CHAR16 *gNvmeBusControllerName = L"NVMe Mass Storage Controller"; + +//================================================================================== +EFI_COMPONENT_NAME2_PROTOCOL gNvmeBusControllerDriverName = { + NvmeBusCtlDriverName, + NvmeBusCtlGetControllerName, + LANGUAGE_CODE_ENGLISH +}; + +//********************************************************************** +//<AMI_PHDR_START> +// +// FUNCTION: NvmeBusCtlDriverName +// +// DESCRIPTION: Retrieves a Unicode string that is the user readable name of +// the EFI Driver. +// +// +// PARAMETERS: +// This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. +// Language - A pointer to a three character ISO 639-2 language identifier. +// This is the language of the driver name that that the caller +// is requesting, and it must match one of the languages specified +// in SupportedLanguages. The number of languages supported by a +// driver is up to the driver writer. +// DriverName - A pointer to the Unicode string to return. This Unicode string +// is the name of the driver specified by This in the language +// specified by Language. +// +// RETURN: +// EFI_SUCCES - The Unicode string for the Driver specified by This +// and the language specified by Language was returned +// in DriverName. +// EFI_INVALID_PARAMETER - Language is NULL. +// EFI_INVALID_PARAMETER - DriverName is NULL. +// EFI_UNSUPPORTED - The driver specified by This does not support the +// language specified by Language. +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeBusCtlDriverName( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName +) +{ + // + //Supports only English + // + if(!Language || !DriverName) return EFI_INVALID_PARAMETER; + if (Strcmp( Language, LANGUAGE_CODE_ENGLISH)) return EFI_UNSUPPORTED; + *DriverName = gNvmeBusDriverName; + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// FUNCTION: NvmeBusCtlGetControllerName +// +// DESCRIPTION: Retrieves a Unicode string that is the user readable name of +// the controller that is being managed by an EFI Driver. +// +// PARAMETERS: +// This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. +// ControllerHandle - The handle of a controller that the driver specified by +// This is managing. This handle specifies the controller +// whose name is to be returned. +// ChildHandle - The handle of the child controller to retrieve the name +// of. This is an optional parameter that may be NULL. It +// will be NULL for device drivers. It will also be NULL +// for a bus drivers that wish to retrieve the name of the +// bus controller. It will not be NULL for a bus driver +// that wishes to retrieve the name of a child controller. +// Language - A pointer to a three character ISO 639-2 language +// identifier. This is the language of the controller name +// that that the caller is requesting, and it must match one +// of the languages specified in SupportedLanguages. The +// number of languages supported by a driver is up to the +// driver writer. +// ControllerName - A pointer to the Unicode string to return. This Unicode +// string is the name of the controller specified by +// ControllerHandle and ChildHandle in the language +// specified by Language from the point of view of the +// driver specified by This. +// +// RETURNS: +// EFI_SUCCESS - The Unicode string for the user readable name in the +// language specified by Language for the driver +// specified by This was returned in DriverName. +// EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. +// EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid +// EFI_HANDLE. +// EFI_INVALID_PARAMETER - Language is NULL. +// EFI_INVALID_PARAMETER - ControllerName is NULL. +// EFI_UNSUPPORTED - The driver specified by This is not currently +// managing the controller specified by +// ControllerHandle and ChildHandle. +// EFI_UNSUPPORTED - The driver specified by This does not support the +// language specified by Language. +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeBusCtlGetControllerName( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName +) +{ + + EFI_STATUS Status; + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController; + ACTIVE_NAMESPACE_DATA *ActiveNameSpace; + EFI_LIST_ENTRY *LinkData; + + // Check if gAmiNvmeControllerProtocolGuid is installed on the device + Status = pBS->OpenProtocol( Controller, + &gAmiNvmeControllerProtocolGuid, + (VOID **)&NvmeController, + gNvmeBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (Status != EFI_SUCCESS && Status != EFI_ALREADY_STARTED) { + return EFI_UNSUPPORTED; + } + + // + //Supports only "en-US" + // + if(!Language || !ControllerName || !Controller) return EFI_INVALID_PARAMETER; + if (Strcmp( Language, LANGUAGE_CODE_ENGLISH)) return EFI_UNSUPPORTED; + + if (ChildHandle == NULL) { + *ControllerName = gNvmeBusControllerName; + return EFI_SUCCESS; + } else { + + for (LinkData = NvmeController->ActiveNameSpaceList.ForwardLink; \ + LinkData != &NvmeController->ActiveNameSpaceList; + LinkData = LinkData->ForwardLink) { + + ActiveNameSpace = _CR(LinkData ,ACTIVE_NAMESPACE_DATA, Link); + + if (ActiveNameSpace->NvmeDeviceHandle == ChildHandle){ + *ControllerName = ActiveNameSpace->UDeviceName->UnicodeString; + return EFI_SUCCESS; + + } + } + } + + return EFI_UNSUPPORTED; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeController.c b/Core/EM/Nvme/NvmeController.c new file mode 100644 index 0000000..de54d60 --- /dev/null +++ b/Core/EM/Nvme/NvmeController.c @@ -0,0 +1,1446 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeController.c 3 5/14/15 2:39a Karthikar $ +// +// $Revision: 3 $ +// +// $Date: 5/14/15 2:39a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeController.c $ +// +// 3 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 +// +// 2 9/04/14 7:47a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// [Files] Nvme.cif +// Nvme.mak +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// [NvmeControllerLib] +// [NvmeSmm] +// [NVMEINT13] +// [NvmeProtocol] +// +// 1 6/20/14 6:27a Anandakrishnanl +// [TAG] EIP172958 +// [Category] New Feature +// [Description] Nvme Driver Intial Checkin +// [Files] Nvme.cif +// Nvme.sdl +// Nvme.mak +// Nvme.sd +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeController.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// NvmeController.h +// +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeController.c +// +// Description: Provides Access to Nvme Controller +// +//<AMI_FHDR_END> +//********************************************************************** + +#include "NvmeIncludes.h" +#include "NvmeBus.h" +#include <AmiLib.h> +#include <AmiDxeLib.h> +#include <Protocol\DevicePath.h> +#include <Protocol\BlockIo.h> + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: SmmStall +// +// Description: Stall Function +// +// Input: +// UINTN Usec +// +// Output: +// NONE +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//<AMI_PHDR_END> +//********************************************************************** +VOID +SmmStall ( + UINTN Usec + ) +{ + UINTN Counter, i; + UINT32 Data32, PrevData; + UINTN Remainder; + + Counter = (UINTN)Div64((Usec * 10), 3, &Remainder); + + if (Remainder != 0) { + Counter++; + } + + // + // Call WaitForTick for Counter + 1 ticks to try to guarantee Counter tick + // periods, thus attempting to ensure Microseconds of stall time. + // + if (Counter != 0) { + + PrevData = IoRead32(PM_BASE_ADDRESS + 8); + for (i=0; i < Counter; ) { + Data32 = IoRead32(PM_BASE_ADDRESS + 8); + if (Data32 < PrevData) { // Reset if there is a overlap + PrevData=Data32; + continue; + } + i += (Data32 - PrevData); + PrevData = Data32; + } + } + return; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: CreateAdditionalSubmissionCompletionQueue +// +// Description: Creates Submission and Completion Queue +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, +// IN UINT16 QueueNumber, +// IN UINT32 QueueSize +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: Can be called recursively +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +CreateAdditionalSubmissionCompletionQueue ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, + IN UINT16 QueueNumber, + IN UINT32 QueueSize +) +{ + + EFI_STATUS Status; + COMPLETION_QUEUE_ENTRY CompletionData; + UINTN AllocatePageSize; + UINT64 QueueAddress = 0; + + // Clear memory + MemSet(NvmeCmdWrapper, sizeof(NVME_COMMAND_WRAPPER), 0); + + // Allocate memory only if the pointer is NULL + if (NvmeController->Queue1CompletionUnAligned == 0) { + AllocatePageSize = NvmeController->MemoryPageSize + QueueSize * sizeof(COMPLETION_QUEUE_ENTRY); + + Status = NvmeController->PciIO->AllocateBuffer (NvmeController->PciIO, + AllocateAnyPages, + EfiRuntimeServicesData, + EFI_SIZE_TO_PAGES(AllocatePageSize), + (VOID **)&(QueueAddress), + EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + NvmeController->Queue1CompletionUnAligned = QueueAddress; + NvmeController->Queue1CompletionUnAlignedSize = EFI_SIZE_TO_PAGES(AllocatePageSize); + NvmeController->Queue1CompletionQueue = (QueueAddress & ~(NvmeController->MemoryPageSize - 1)) + + NvmeController->MemoryPageSize; + + NvmeController->Queue1CompletionQueueSize = QueueSize; + + MemSet((VOID *)NvmeController->Queue1CompletionQueue, \ + NvmeController->Queue1CompletionQueueSize * sizeof (COMPLETION_QUEUE_ENTRY), 0); + + Status = NvmeController->PciIO->Map ( NvmeController->PciIO, + EfiPciIoOperationBusMasterCommonBuffer, + (VOID *)NvmeController->Queue1CompletionQueue, + &AllocatePageSize, + &NvmeController->Queue1CompletionQueueMappedAddr, + &NvmeController->Queue1CompletionQueueUnMap + ); + + if (EFI_ERROR(Status)) { + return Status; + } + } + + // Build NVME command + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = CREATE_IO_COMPLETION_QUEUE; + NvmeCmdWrapper->NvmCmd.CMD0.FusedOperation = 0; + NvmeCmdWrapper->NvmCmd.CMD0.PSDT = 0; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeController->CommandIdentifierAdmin; + NvmeCmdWrapper->NvmCmd.NSID = 0; + + NvmeCmdWrapper->NvmCmd.PRP1 = (UINT64)NvmeController->Queue1CompletionQueueMappedAddr; + NvmeCmdWrapper->NvmCmd.PRP2 = 0; + NvmeCmdWrapper->NvmCmd.CDW10 = ((QueueSize - 1) << 16 )+ QueueNumber; + NvmeCmdWrapper->NvmCmd.CDW11 = 1; // Contiguous + + NvmeCmdWrapper->AdminOrNVMCmdSet = TRUE; + NvmeCmdWrapper->SQIdentifier = 0; // Cmd issued in Queue0 + NvmeCmdWrapper->CmdTimeOut = 1000; + + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, &CompletionData); + + if (EFI_ERROR(Status)) { + goto CreateAdditionalSubmissionCompletionQueue_Exit; + } + + // Allocate memory only if the pointer is NULL + if (NvmeController->Queue1SubmissionUnAligned == 0) { + + AllocatePageSize = NvmeController->MemoryPageSize + + QueueSize * sizeof(NVME_ADMIN_COMMAND); + + Status = NvmeController->PciIO->AllocateBuffer (NvmeController->PciIO, + AllocateAnyPages, + EfiRuntimeServicesData, + EFI_SIZE_TO_PAGES(AllocatePageSize), + (VOID **)&(QueueAddress), + EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + NvmeController->Queue1SubmissionUnAligned = QueueAddress; + NvmeController->Queue1SubmissionUnAlignedSize = EFI_SIZE_TO_PAGES(AllocatePageSize); + NvmeController->Queue1SubmissionQueue = (QueueAddress & ~(NvmeController->MemoryPageSize - 1)) + + NvmeController->MemoryPageSize; + + NvmeController->Queue1SubmissionQueueSize = QueueSize; + MemSet((VOID *)NvmeController->Queue1SubmissionQueue, \ + NvmeController->Queue1SubmissionQueueSize * sizeof(NVME_ADMIN_COMMAND), 0); + + Status = NvmeController->PciIO->Map ( NvmeController->PciIO, + EfiPciIoOperationBusMasterCommonBuffer, + (VOID *)NvmeController->Queue1SubmissionQueue, + &AllocatePageSize, + &NvmeController->Queue1SubmissionQueueMappedAddr, + &NvmeController->Queue1SubmissionQueueUnMap + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + } + + // Build NVME command + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = CREATE_IO_SUBMISSION_QUEUE; + NvmeCmdWrapper->NvmCmd.CMD0.FusedOperation = 0; + NvmeCmdWrapper->NvmCmd.CMD0.PSDT = 0; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeController->CommandIdentifierAdmin; + NvmeCmdWrapper->NvmCmd.NSID = 0; + + NvmeCmdWrapper->NvmCmd.PRP1 = (UINT64)NvmeController->Queue1SubmissionQueueMappedAddr; + NvmeCmdWrapper->NvmCmd.PRP2 = 0; + NvmeCmdWrapper->NvmCmd.CDW10 = ((QueueSize - 1) << 16 )+ QueueNumber; + NvmeCmdWrapper->NvmCmd.CDW11 = (QueueNumber << 16) + 1; // Contiguous + + NvmeCmdWrapper->AdminOrNVMCmdSet = TRUE; + NvmeCmdWrapper->SQIdentifier = 0; // Cmd issued to admin queue + NvmeCmdWrapper->CmdTimeOut = 1000; + + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, &CompletionData); + + CreateAdditionalSubmissionCompletionQueue_Exit: + + NvmeController->Queue1PhaseTag = FALSE; + + NvmeController->Queue1SubmissionQueueTailPtr = 0; + NvmeController->Queue1SubmissionQueueHeadPtr = 0; + + NvmeController->Queue1CompletionQueueTailPtr = 0; + NvmeController->Queue1CompletionQueueHeadPtr = 0; + + return Status; + +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: ProgramPRP2List +// +// Description: Programs PRP2 with the list of page address for data transfer +// +// Input: +// IN EFI_BLOCK_IO_PROTOCOL *This +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +ProgramPRP2List ( + IN UINT64 *PRP2List, + IN UINT32 PageSize, + IN UINTN BufferAddress, + IN UINTN BufferSize, + IN UINTN *PRP2TransferSize +) +{ + + UINTN TotalNumberOfEntries = PageSize / 8; // Each entry 64 bytes long + + *PRP2TransferSize = 0; + + do { + + *PRP2List++ = BufferAddress; + if (BufferSize >= PageSize) { + *PRP2TransferSize += PageSize; + BufferAddress += PageSize; + BufferSize -= PageSize; + } else { + *PRP2TransferSize = *PRP2TransferSize + (UINT32)BufferSize; + BufferAddress += BufferSize; + BufferSize = 0; + } + + } while (--TotalNumberOfEntries && (BufferSize > 0)); + + return EFI_SUCCESS; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeReadWriteBlocks +// +// Description: Read/Write data from the given LBA address +// +// Input: +// IN ACTIVE_NAMESPACE_DATA *ActiveNameSpace, +// IN UINT32 MediaId, +// IN EFI_LBA LBA, +// IN UINTN BufferSize, +// OUT VOID *Buffer +// IN UINT8 ReadWriteOpCode +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS +NvmeReadWriteBlocks( + IN ACTIVE_NAMESPACE_DATA *ActiveNameSpace, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer, + OUT COMPLETION_QUEUE_ENTRY *NvmeCompletionData, + IN UINT8 ReadWriteOpCode +) +{ + + EFI_STATUS Status = EFI_SUCCESS; + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController = ActiveNameSpace->NvmeController; + EFI_BLOCK_IO_MEDIA *BlkMedia = ActiveNameSpace->NvmeBlockIO.Media; + NVME_COMMAND_WRAPPER *NvmeCmdWrapper = NvmeController->NvmeCmdWrapper; + COMPLETION_QUEUE_ENTRY CompletionData; + COMPLETION_QUEUE_ENTRY *pCompletionData = &CompletionData; + UINTN DataN; + UINT32 LBACountInOneTransfer; + UINTN PRP1TransferSize; + UINTN PRP2TransferSize; + UINTN MappedBufferSize = BufferSize; + EFI_PHYSICAL_ADDRESS MappedBuffer; + VOID *BufferUnMap; + + if (!NvmeController->NvmeInSmm) { + TRACE((-1,"LBA : %lx BufferSize : %lx Buffer : %lx Opcode : %x", LBA, BufferSize, Buffer, ReadWriteOpCode)); + } + + // Check if Media ID matches + if (BlkMedia->MediaId != MediaId) { + return EFI_MEDIA_CHANGED; + } + + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + // + // If IoAlign values is 0 or 1, means that the buffer can be placed + // anywhere in memory or else IoAlign value should be power of 2. To be + // properly aligned the buffer address should be divisible by IoAlign + // with no remainder. + // + if((BlkMedia->IoAlign > 1 ) && ((UINTN)Buffer % BlkMedia->IoAlign)) { + return EFI_INVALID_PARAMETER; + } + + // Check whether the block size is multiple of BlkMedia->BlockSize + DataN = BufferSize % BlkMedia->BlockSize; + if (DataN){ + return EFI_BAD_BUFFER_SIZE; + } + + // Check for Valid start LBA # + if (LBA > BlkMedia->LastBlock) { + return EFI_INVALID_PARAMETER; + } + + // Check for Valid End LBA # + DataN = BufferSize / BlkMedia->BlockSize; + if (LBA + DataN > BlkMedia->LastBlock + 1) { + return EFI_INVALID_PARAMETER; + } + + do { + // Limit the transfer size to MDTS value + if (NvmeController->IdentifyControllerData->MDTS && (MappedBufferSize > (UINTN)(Mul64(Shl64(1, NvmeController->IdentifyControllerData->MDTS), NvmeController->MemoryPageSizeMin)))){ + MappedBufferSize = (UINTN)Mul64(Shl64(1, NvmeController->IdentifyControllerData->MDTS), NvmeController->MemoryPageSizeMin); + } + + + // After MAP, Mapped BufferSize may not be same as input. + // So need to complete the transfer in multiple loops. + // When the call originates from SMM, don't call Map function + MappedBuffer = (EFI_PHYSICAL_ADDRESS) Buffer; + if (!NvmeController->NvmeInSmm) { + + Status = NvmeController->PciIO->Map ( NvmeController->PciIO, + ((ReadWriteOpCode == NVME_READ) || (ReadWriteOpCode == NVME_COMPARE)) ? EfiPciIoOperationBusMasterWrite : EfiPciIoOperationBusMasterRead, + Buffer, + &MappedBufferSize, + &MappedBuffer, + &BufferUnMap + ); + if (EFI_ERROR(Status)) { + return Status; + } + } + + MemSet(NvmeCmdWrapper, sizeof(NVME_COMMAND_WRAPPER), 0); + LBACountInOneTransfer = 0; + + PRP2TransferSize = 0; + + NvmeCmdWrapper->NvmCmd.PRP1 = (UINT64) MappedBuffer; + PRP1TransferSize = NvmeController->MemoryPageSize - + (MappedBuffer & ((UINTN)(NvmeController->MemoryPageSize) - 1)); + + // If all data can be transferred using only PRP1 then do that. + if (PRP1TransferSize >= MappedBufferSize) { + PRP1TransferSize = MappedBufferSize; + } + + // Do we need PRP2 + if (MappedBufferSize - PRP1TransferSize) { + + // Do we need either a PRP2 pointer or a List + if (MappedBufferSize - PRP1TransferSize <= NvmeController->MemoryPageSize) { + NvmeCmdWrapper->NvmCmd.PRP2 = NvmeCmdWrapper->NvmCmd.PRP1 + PRP1TransferSize; + PRP2TransferSize = MappedBufferSize - PRP1TransferSize; + } else { + // We need PRP2 List + Status = ProgramPRP2List (ActiveNameSpace->PRP2List, NvmeController->MemoryPageSize, \ + (UINTN)MappedBuffer + PRP1TransferSize, \ + MappedBufferSize - PRP1TransferSize, &PRP2TransferSize + ); + + if (EFI_ERROR(Status)) { + break; + } + + NvmeCmdWrapper->NvmCmd.PRP2 = (UINT64) ActiveNameSpace->PRP2ListMappedAddr; + } + } + + LBACountInOneTransfer = (UINT32)((PRP1TransferSize + PRP2TransferSize) / BlkMedia->BlockSize); + + // Build NVME command + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = ReadWriteOpCode; + NvmeCmdWrapper->NvmCmd.CMD0.FusedOperation = 0; + NvmeCmdWrapper->NvmCmd.CMD0.PSDT = 0; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeController->CommandIdentifierQueue1; + NvmeCmdWrapper->NvmCmd.NSID = ActiveNameSpace->ActiveNameSpaceID; + + NvmeCmdWrapper->NvmCmd.MPTR = 0; + NvmeCmdWrapper->NvmCmd.CDW10 = (UINT32)LBA; + NvmeCmdWrapper->NvmCmd.CDW11 = (UINT32)Shr64(LBA, 32); + NvmeCmdWrapper->NvmCmd.CDW12 = 0x80000000 + (LBACountInOneTransfer - 1); + NvmeCmdWrapper->NvmCmd.CDW13 = 0; + NvmeCmdWrapper->NvmCmd.CDW14 = 0; + + NvmeCmdWrapper->AdminOrNVMCmdSet = FALSE; + NvmeCmdWrapper->SQIdentifier = NvmeController->NVMQueueNumber; + NvmeCmdWrapper->CmdTimeOut = 1000; + + // If caller has passed buffer to return controller status, use it. + if (NvmeCompletionData) { + pCompletionData = NvmeCompletionData; + } + + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, pCompletionData); + + if (EFI_ERROR(Status)) { + if (!NvmeController->NvmeInSmm) { + NvmeController->PciIO->Unmap(NvmeController->PciIO, BufferUnMap); + } + break; + } + + // Remaining Bytes to be transferred + MappedBufferSize -= (LBACountInOneTransfer * BlkMedia->BlockSize); + + // Update LBA # for next transfer if needed + LBA += LBACountInOneTransfer; + + // Adjust the Buffer address + Buffer =(VOID*) ((UINTN) Buffer + (LBACountInOneTransfer * BlkMedia->BlockSize)); + BufferSize -= (LBACountInOneTransfer * BlkMedia->BlockSize); + + // When PciIO->Map is called, it might not map the complete buffer. + // After the complete MappedBufferSize is transferred, if there is a left over do that transfer also + if (MappedBufferSize == 0) { + MappedBufferSize = BufferSize; + } + + if (!NvmeController->NvmeInSmm) { + NvmeController->PciIO->Unmap(NvmeController->PciIO, BufferUnMap); + } + + } while (MappedBufferSize); + + if (!NvmeController->NvmeInSmm) { + TRACE((-1,"%r \n", Status)); + } + + return Status; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: ExecuteNvmeCmd +// +// Description: Execute Admin and Nvme cmds +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, +// OUT COMPLETION_QUEUE_ENTRY *CmdCompletionData +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: If the cmd needs to be retried due to a failure, caller can initialize the RetryCount. +// Can be called recursively. +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +ExecuteNvmeCmd ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, + OUT COMPLETION_QUEUE_ENTRY *CmdCompletionData +) + +{ + EFI_STATUS Status; + + do { + // Because of recursive nature and retry mechnism, cmd identifer needs to be updated just before giving the call. + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeCmdWrapper->AdminOrNVMCmdSet ? NvmeController->CommandIdentifierAdmin : \ + NvmeController->CommandIdentifierQueue1; + + NvmeCmdWrapper->AdminOrNVMCmdSet ? (Status = AddToAdminSubmissionQueue(NvmeController, NvmeCmdWrapper)) : \ + (Status = AddToQueue1SubmissionQueue(NvmeController, NvmeCmdWrapper)); + + if (EFI_ERROR(Status)) { + continue; + } + + Status = UpdateDoorBellRegister(NvmeController, + NvmeCmdWrapper->SQIdentifier, + NvmeCmdWrapper->AdminOrNVMCmdSet ? NvmeController->AdminSubmissionQueueTailPtr : + NvmeController->Queue1SubmissionQueueTailPtr + ); + + if (EFI_ERROR(Status)) { + continue; + } + + //Wait for cmd to complete + if (NvmeCmdWrapper->NvmCmd.CMD0.Opcode != ASYNC_EVENT_REQUEST) { + Status = WaitForCompletionQueueUpdate(NvmeController, NvmeCmdWrapper, CmdCompletionData); + } + + } while (EFI_ERROR(Status) && NvmeCmdWrapper->RetryCount--); + + return Status; + +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: AddToAdminSubmissionQueue +// +// Description: Submits the cmd to the Admin Submission queue +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +AddToAdminSubmissionQueue ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper +) +{ + EFI_STATUS Status; + UINT64 DestinationAddress; + + // Is Admin Queue full? + if (NvmeController->AdminSubmissionQueueHeadPtr) { // Non-zero value + if ((NvmeController->AdminSubmissionQueueTailPtr - 1) == NvmeController->AdminSubmissionQueueHeadPtr){ + + // In this design, queue should never get filled up. + // If it does something is wrong. Delete and start all over again. + + Status = RecreateAllQueues (NvmeController); + if (EFI_ERROR(Status)) { + return EFI_OUT_OF_RESOURCES; + } + + } + } else { + // If Head is at the start and Tail is at the end, then queue is full + if (NvmeController->AdminSubmissionQueueTailPtr == (NvmeController->AdminSubmissionQueueHeadPtr + + NvmeController->AdminSubmissionQueueSize - 1)) { + + // In this design, queue should never get filled up. + // If it does something is wrong. Delete and start all over again. + Status = RecreateAllQueues (NvmeController); + if (EFI_ERROR(Status)) { + return EFI_OUT_OF_RESOURCES; + } + } + } + + // Copy cmd to Admin Queue + DestinationAddress = NvmeController->AdminSubmissionQueue + ( + NvmeController->AdminSubmissionQueueTailPtr * sizeof(NVME_ADMIN_COMMAND)); + +#if NVME_VERBOSE_PRINT + if (!NvmeController->NvmeInSmm) { + TRACE((-1, "Destination Address for Cmd : %016lx\n", DestinationAddress)); + } +#endif + + MemCpy ((VOID *)DestinationAddress, &(NvmeCmdWrapper->NvmCmd), sizeof(NVME_ADMIN_COMMAND)); + + NvmeController->AdminSubmissionQueueTailPtr++; + + // Check if there is a roller over + if (NvmeController->AdminSubmissionQueueTailPtr >= (NvmeController->AdminSubmissionQueueSize)) { + NvmeController->AdminSubmissionQueueTailPtr = 0; + } + + return EFI_SUCCESS; + +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: AddToQueue1SubmissionQueue +// +// Description: Submits the Nvme cmd to the Queue1 Submission queue +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +AddToQueue1SubmissionQueue ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper +) +{ + EFI_STATUS Status; + UINT64 DestinationAddress; + + // Is Queue full? If Tail is one less than the Head queue is full. + if (NvmeController->Queue1SubmissionQueueHeadPtr) { // Non-zero value + if ((NvmeController->Queue1SubmissionQueueTailPtr - 1) == NvmeController->Queue1SubmissionQueueHeadPtr){ + + // In this design, queue should never get filled up. + // If it does something is wrong. Delete and start all over again. + Status = RecreateQueue1 (NvmeController); + if (EFI_ERROR(Status)) { + return EFI_OUT_OF_RESOURCES; + } + + } + } else { + // If Head is at the start and Tail is at the end, then queue is full + if (NvmeController->Queue1SubmissionQueueTailPtr == (NvmeController->Queue1SubmissionQueueHeadPtr + + NvmeController->Queue1SubmissionQueueSize - 1)) { + + // In this design, queue should never get filled up. + // If it does something is wrong. Delete and start all over again. + + Status = RecreateQueue1 (NvmeController); + if (EFI_ERROR(Status)) { + return EFI_OUT_OF_RESOURCES; + } + } + } + + // Copy cmd to Admin Queue + DestinationAddress = NvmeController->Queue1SubmissionQueue + + (NvmeController->Queue1SubmissionQueueTailPtr * sizeof(NVME_ADMIN_COMMAND)); + +#if NVME_VERBOSE_PRINT + if (!NvmeController->NvmeInSmm) { + TRACE((-1, "Destination Address for Cmd : %016lx\n", DestinationAddress)); + } +#endif + + MemCpy ((VOID *)DestinationAddress, &(NvmeCmdWrapper->NvmCmd), sizeof(NVME_ADMIN_COMMAND)); + + NvmeController->Queue1SubmissionQueueTailPtr++; + + // Check if there is a roller over + if (NvmeController->Queue1SubmissionQueueTailPtr >= NvmeController->Queue1SubmissionQueueSize) { + NvmeController->Queue1SubmissionQueueTailPtr = 0; + } + + return EFI_SUCCESS; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: UpdateDoorBellRegister +// +// Description: Update door bell register for the controller to start executing the cmd +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// IN UINT16 QueueNumber, +// IN UINT32 Value +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +UpdateDoorBellRegister ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN UINT16 QueueNumber, + IN UINT32 Value +) +{ + + UINT32 Offset; + + // Update Door Bell Register + Offset = QUEUE_DOORBELL_OFFSET(QueueNumber, 0, NvmeController->DoorBellStride); + +#if NVME_VERBOSE_PRINT + if (!NvmeController->NvmeInSmm) { + TRACE((-1, "\nDoorBell Offset %016lx Value %08X\n", NvmeController->NvmeBarOffset + Offset, Value)); + } +#endif + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset) = Value; + return EFI_SUCCESS; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: WaitForCompletionQueueUpdate +// +// Description: Checks for the completion queue for the correct PhaseTag, Queue Identified and Cmd Identifier +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, +// IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, +// OUT COMPLETION_QUEUE_ENTRY *CmdCompletionData +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +WaitForCompletionQueueUpdate ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + IN NVME_COMMAND_WRAPPER *NvmeCmdWrapper, + OUT COMPLETION_QUEUE_ENTRY *CmdCompletionData +) +{ + + EFI_STATUS Status; + UINT32 TimeOut = NvmeCmdWrapper->CmdTimeOut; + UINT32 Offset; + COMPLETION_QUEUE_ENTRY *pCmdCompletionData; + UINT16 CommandIdentifier = NvmeCmdWrapper->AdminOrNVMCmdSet ? NvmeController->CommandIdentifierAdmin : \ + NvmeController->CommandIdentifierQueue1; + + UINT64 CompletionQueueStart = NvmeCmdWrapper->AdminOrNVMCmdSet ? NvmeController->AdminCompletionQueue : \ + NvmeController->Queue1CompletionQueue; + + UINT16 CompletionQueueHeadPtr = NvmeCmdWrapper->AdminOrNVMCmdSet ? NvmeController->AdminCompletionQueueHeadPtr :\ + NvmeController->Queue1CompletionQueueHeadPtr; + + // Toggle extected phasetag on every rollover + if (CompletionQueueHeadPtr == 0) { + NvmeCmdWrapper->AdminOrNVMCmdSet ? (NvmeController->AdminPhaseTag = ~NvmeController->AdminPhaseTag) : \ + (NvmeController->Queue1PhaseTag = ~NvmeController->Queue1PhaseTag); + } + + // Get the offset to the Command Completion Queue Head Ptr + pCmdCompletionData = (COMPLETION_QUEUE_ENTRY *)(CompletionQueueStart + CompletionQueueHeadPtr * sizeof(COMPLETION_QUEUE_ENTRY)); + + do { + // Check whether Command Identifier, SQ ID matches and Phase Tag matches with the cmd issued. + if ((pCmdCompletionData->CommandIdentifier == CommandIdentifier) && \ + (pCmdCompletionData->SQIdentifier == NvmeCmdWrapper->SQIdentifier) && \ + (pCmdCompletionData->PhaseTag == (NvmeCmdWrapper->AdminOrNVMCmdSet ? NvmeController->AdminPhaseTag : NvmeController->Queue1PhaseTag))) + { + break; + } + + // check if there are any fatal errors + if (CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CSTS) & CSTS_CFS){ + if (!NvmeController->NvmeInSmm) { + TRACE((-1, "Nvme Fatal Error\n")); + } + return EFI_DEVICE_ERROR; + + } + + if (!NvmeController->NvmeInSmm) { + pBS->Stall(1000); // 1msec delay + } else { + SmmStall (1000); + } + } while (--TimeOut); + + if (!NvmeController->NvmeInSmm) { + PrintCommandCompletionData (pCmdCompletionData); + } + + if (!TimeOut) { + + // This is a fatal condition. We should expect some kind of response from the controller. + // If not we have to either wait for more time or delete and recreate the queue + + NvmeCmdWrapper->AdminOrNVMCmdSet ? NvmeController->CommandIdentifierAdmin++ : \ + NvmeController->CommandIdentifierQueue1++; + + if (NvmeCmdWrapper->AdminOrNVMCmdSet) { + Status = RecreateAllQueues(NvmeController); + } else { + Status = RecreateQueue1(NvmeController); + } + + if (EFI_ERROR(Status)) { + // If recreating the queue gets an error. nothing can be done. + NvmeCmdWrapper->RetryCount = 0; + } else { + // Retry the cmd one more time + NvmeCmdWrapper->RetryCount++; + } + + return EFI_DEVICE_ERROR; + } + + // Update HeadPtr from Completion Queue. + // Check what Queue was cmd posted to and then update the corresponding Head/Tail ptr + if (NvmeCmdWrapper->AdminOrNVMCmdSet) { + NvmeController->AdminSubmissionQueueHeadPtr = pCmdCompletionData->SQHeadPointer; + NvmeController->AdminCompletionQueueHeadPtr = NvmeController->AdminSubmissionQueueHeadPtr; + Offset = QUEUE_DOORBELL_OFFSET(NvmeCmdWrapper->SQIdentifier, 1, NvmeController->DoorBellStride); + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset) = NvmeController->AdminCompletionQueueHeadPtr; + } else { + NvmeController->Queue1SubmissionQueueHeadPtr = pCmdCompletionData->SQHeadPointer; + NvmeController->Queue1CompletionQueueHeadPtr = NvmeController->Queue1SubmissionQueueHeadPtr; + Offset = QUEUE_DOORBELL_OFFSET(NvmeCmdWrapper->SQIdentifier, 1, NvmeController->DoorBellStride); + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset) = NvmeController->Queue1CompletionQueueHeadPtr; + } + + // Todo Todo + // Check whether all cmds submitted has been completed. CompletionQueue Head Ptr should give a clue on + // how many cmds where executed. + if (pCmdCompletionData->StatusCode || pCmdCompletionData->StatusCodeType) { + Status = EFI_DEVICE_ERROR; + } else { + Status = EFI_SUCCESS; + } + +#if NVME_VERBOSE_PRINT + if (!NvmeController->NvmeInSmm) { + if (NvmeCmdWrapper->AdminOrNVMCmdSet) { + TRACE((-1, "AdminSubmissionQueueHeadPtr %08X\n", NvmeController->AdminSubmissionQueueHeadPtr)); + TRACE((-1, "AdminSubmissionQueueTailPtr %08X\n", NvmeController->AdminSubmissionQueueTailPtr)); + TRACE((-1, "AdminCompletionQueueHeadPtr %08X\n", NvmeController->AdminCompletionQueueHeadPtr)); + TRACE((-1, "AdminCompletionQueueTailPtr %08X\n", NvmeController->AdminCompletionQueueTailPtr)); + } else { + TRACE((-1, "Queue1SubmissionQueueHeadPtr %08X\n", NvmeController->Queue1SubmissionQueueHeadPtr)); + TRACE((-1, "Queue1SubmissionQueueTailPtr %08X\n", NvmeController->Queue1SubmissionQueueTailPtr)); + TRACE((-1, "Queue1CompletionQueueHeadPtr %08X\n", NvmeController->Queue1CompletionQueueHeadPtr)); + TRACE((-1, "Queue1CompletionQueueTailPtr %08X\n", NvmeController->Queue1CompletionQueueTailPtr)); + } + } +#endif + + // Update o/p buffer + MemCpy ((VOID *)CmdCompletionData, pCmdCompletionData, sizeof(COMPLETION_QUEUE_ENTRY)); + NvmeCmdWrapper->AdminOrNVMCmdSet ? NvmeController->CommandIdentifierAdmin++ : NvmeController->CommandIdentifierQueue1++; + + return Status; + +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: RecreateAllQueues +// +// Description: Delete Admin and other Completion/Submission queue and create it back again. +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: This procedure will be called if the queue gets filled up. This situation shouldn't generally happen as each cmd +// is completed in our case. So both Head and Tail should point to the same location before and after cmd is executed. +// One possibility for calling this routine will be when the cmd doesn't get completed and Completion Queue doesn't get updated +// by the controller. Also any Set Feature cmd that was issued during initilization should be re-issued here. +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +RecreateAllQueues ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +) +{ + + EFI_STATUS Status = EFI_SUCCESS; + UINT32 ProgramCC = 0; + UINT32 Delay; + + + // In SMM, this function is not supported + if (NvmeController->NvmeInSmm) { + return EFI_DEVICE_ERROR; + } + +#if NVME_VERBOSE_PRINT + if (!NvmeController->NvmeInSmm) { + TRACE((-1, "Recreate Admin Queue : ")); + } +#endif + + ProgramCC = CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CC); + + // Check if the controller is already running. If yes stop it. + Delay = NvmeController->TimeOut * 500; + if (CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CC) & 0x1) { + + // Clear Control register + CONTROLLER_REG32 (NvmeController->NvmeBarOffset, Offset_CC) = 0; + do { + if (!(CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CSTS) & 0x1)) { + break; + } + + if (!NvmeController->NvmeInSmm) { + pBS->Stall(1000); // 1msec delay + } + else { + SmmStall (1000); + } + + } while (--Delay); + + } + + if (!Delay) { + goto RecreateAllQueues_Error; + } + + // Program Admin Queue Size and Base Address + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Aqa) = + (UINT32)(Shl64((NvmeController->AdminCompletionQueueSize - 1), 16) + (NvmeController->AdminSubmissionQueueSize - 1)); + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Asq) = + (UINT32) NvmeController->AdminSubmissionQueue; + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Asq + 4) = + (UINT32)Shr64(NvmeController->AdminSubmissionQueue, 32); + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Acq) = + (UINT32)NvmeController->AdminCompletionQueue; + + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_Acq + 4) = + (UINT32)Shr64(NvmeController->AdminCompletionQueue, 32); + + NvmeController->AdminPhaseTag = FALSE; + + // Enable Controller + CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CC) = (ProgramCC | 1); + + // Wait for the controller to get ready + // Check if the cobtroller is already running. If yes stop it. + Delay = NvmeController->TimeOut * 500; + do { + if ((CONTROLLER_REG32(NvmeController->NvmeBarOffset, Offset_CSTS) & 0x1)) { + break; + } + + if (!NvmeController->NvmeInSmm) { + pBS->Stall(1000); // 1msec delay + } + else { + SmmStall (1000); + } + + } while (--Delay); + +RecreateAllQueues_Error: + + if (!Delay) { + Status = EFI_DEVICE_ERROR; + +#if NVME_VERBOSE_PRINT + if (!NvmeController->NvmeInSmm) { + TRACE((-1, "Status %r\n", Status)); + } +#endif + + return Status; + } + + NvmeController->AdminSubmissionQueueHeadPtr = 0; + NvmeController->AdminSubmissionQueueTailPtr = 0; + NvmeController->AdminCompletionQueueHeadPtr = 0; + NvmeController->AdminCompletionQueueTailPtr = 0; + NvmeController->AdminPhaseTag = FALSE; + + if (!NvmeController->ReInitializingQueue1) { + Status = RecreateQueue1 (NvmeController); + } + + return Status; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: RecreateQueue1 +// +// Description: Delete Completion and Submission queue and create it back again. +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: This procedure will be called if the queue gets filled up. This situation shouldn't generally happen as each cmd +// is completed in our case. So both Head and Tail should point to the same location before and after cmd is executed. +// One possibility for calling this routine will be when the cmd doesn't get completed and Completion Queue doesn't get updated +// by the controller. Can be called recursively. +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +RecreateQueue1 ( + IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +) +{ + + EFI_STATUS Status; + NVME_COMMAND_WRAPPER *NvmeCmdWrapper; + COMPLETION_QUEUE_ENTRY CompletionData; + + // In SMM, this function not supported + if (NvmeController->NvmeInSmm) { + return EFI_DEVICE_ERROR; + } + +#if NVME_VERBOSE_PRINT + if (!NvmeController->NvmeInSmm) { + TRACE((-1, "Recreate Queue1 : ")); + } +#endif + + NvmeController->ReInitializingQueue1 = TRUE; + + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof(NVME_COMMAND_WRAPPER), + (VOID**)&NvmeCmdWrapper + ); + + if (EFI_ERROR(Status)) { + NvmeController->ReInitializingQueue1 = FALSE; + return Status; + } + + // Clear memory + MemSet(NvmeCmdWrapper, sizeof(NVME_COMMAND_WRAPPER), 0); + + // Build NVME command to delete Submission queue + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = DELETE_IO_SUBMISSION_QUEUE; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeController->CommandIdentifierAdmin; + NvmeCmdWrapper->NvmCmd.CDW10 = NvmeController->NVMQueueNumber; + + NvmeCmdWrapper->AdminOrNVMCmdSet = TRUE; + NvmeCmdWrapper->SQIdentifier = 0; // Queue 0 for Admin cmds + NvmeCmdWrapper->CmdTimeOut = 1000; + + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, &CompletionData); + if (EFI_ERROR(Status)) { + goto RecreateQueue1_Error; + } + + // Build NVME command to delete Completion queue + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = DELETE_IO_COMPLETION_QUEUE; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = NvmeController->CommandIdentifierAdmin; + NvmeCmdWrapper->NvmCmd.CDW10 = NvmeController->NVMQueueNumber; + + NvmeCmdWrapper->AdminOrNVMCmdSet = TRUE; + NvmeCmdWrapper->SQIdentifier = 0; // Queue 0 for Admin cmds + NvmeCmdWrapper->CmdTimeOut = 1000; + + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, &CompletionData); + if (EFI_ERROR(Status)) { + goto RecreateQueue1_Error; + } + + // Create Submission and Completion Queue1 + Status = CreateAdditionalSubmissionCompletionQueue( + NvmeController, + NvmeCmdWrapper, + NvmeController->NVMQueueNumber, + NvmeController->Queue1SubmissionQueueSize + ); + +RecreateQueue1_Error: + + NvmeController->ReInitializingQueue1 = FALSE; + + pBS->FreePool (NvmeCmdWrapper); + +#if NVME_VERBOSE_PRINT + if (!NvmeController->NvmeInSmm) { + TRACE((-1, "Status %r\n", Status)); + } +#endif + + return Status; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: PrintCommandCompletionData +// +// Description: Prints the cmd completion status +// +// Input: +// IN COMPLETION_QUEUE_ENTRY *pCmdCompletionData +// +// Output: +// NONE +// +// Modified: +// +// Referrals: +// +// Notes: The amount of data that will get printed can be controlled +// using DEBUG_ERROR_LEVEL_MASK SDL token. +// Make sure PcdDebugPrintErrorLevel is properly cloned and set to +// PcdsPatchableInModule in the project. +// +//<AMI_PHDR_END> +//********************************************************************** + +VOID +PrintCommandCompletionData ( + IN COMPLETION_QUEUE_ENTRY *pCmdCompletionData +) +{ + +#if NVME_VERBOSE_PRINT + // Fig 25 NVM Express 1.1 spec + // Print Completion Cmd Data + TRACE((-1, "Completion Queue DW2 : %08X\n", *((UINT32 *)pCmdCompletionData + 2))); + TRACE((-1, "Completion Queue DW3 : %08X\n", *((UINT32 *)pCmdCompletionData + 3))); + TRACE((-1, "Completion Queue DW0 : %08X\n", pCmdCompletionData->DW0)); + TRACE((-1, "Completion Queue Reserved : %08X\n", pCmdCompletionData->DW1)); +#endif + +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: PrintNvmeCmdWrapper +// +// Description: Prints Nvme cmd parameters +// +// Input: +// NVME_COMMAND_WRAPPER *NvmeCmdWrapper +// +// Output: +// NONE +// +// Modified: +// +// Referrals: +// +// Notes: The amount of data that will get printed can be controlled +// using DEBUG_ERROR_LEVEL_MASK SDL token. +// Make sure PcdDebugPrintErrorLevel is properly cloned and set to +// PcdsPatchableInModule in the project. +// +//<AMI_PHDR_END> +//********************************************************************** +VOID +PrintNvmeCmdWrapper ( + NVME_COMMAND_WRAPPER *NvmeCmdWrapper +) +{ + + +#if NVME_VERBOSE_PRINT + TRACE((-1,"\nCMD DW0 : %08X\n", *(UINT32 *)&(NvmeCmdWrapper->NvmCmd))); + TRACE((-1, "MPTR : %016lX\n", NvmeCmdWrapper->NvmCmd.MPTR)); + TRACE((-1, "PRP1 : %016lX\n", NvmeCmdWrapper->NvmCmd.PRP1)); + TRACE((-1, "PRP2 : %016lX\n", NvmeCmdWrapper->NvmCmd.PRP2)); + TRACE((-1, "CDW10 : %08X\n", NvmeCmdWrapper->NvmCmd.CDW10)); + TRACE((-1, "CDW11 : %08X\n", NvmeCmdWrapper->NvmCmd.CDW11)); + TRACE((-1, "CDW12 : %08X\n", NvmeCmdWrapper->NvmCmd.CDW12)); + TRACE((-1, "CDW13 : %08X\n", NvmeCmdWrapper->NvmCmd.CDW13)); + TRACE((-1, "CDW14 : %08X\n", NvmeCmdWrapper->NvmCmd.CDW14)); + TRACE((-1, "CDW15 : %08X\n", NvmeCmdWrapper->NvmCmd.CDW15)); + TRACE((-1, "Cmd sent to Queue : %08X\n", NvmeCmdWrapper->SQIdentifier)); +#endif + +} + +//********************************************************************** +//<AMI_PHDR_START> +// Procedure: UnicodeStrToAsciiStr +// +// Description: This function converts the content of the Unicode string Source +// to the ASCII string Destination by copying the lower 8 bits of +// each Unicode character and returns Destination +// +// Input: Source A pointer to a Null-terminated Unicode string. +// Destination A pointer to a Null-terminated ASCII string. +// +// Output: None +// +//<AMI_PHDR_END> +//********************************************************************** +CHAR8* +UnicodeStrToAsciiStr ( + IN CONST CHAR16 *Source, + OUT CHAR8 *Destination + ) +{ + CHAR8 *ReturnValue; + UINTN TempReturnValue; + UINTN TempSource; + + ASSERT (Destination != NULL); + // + // ASSERT if Source is long than PcdMaximumUnicodeStringLength. + // Length tests are performed inside StrLen(). + // + TempSource = (Wcslen ((CHAR16 *)Source) + 1) * sizeof (*Source); + ASSERT (TempSource != 0); + // + // Source and Destination should not overlap + // + ASSERT ((UINTN) ((CHAR16 *) Destination - Source) > Wcslen ((CHAR16 *)Source)); + ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > Wcslen ((CHAR16 *)Source)); + + + ReturnValue = Destination; + while (*Source != '\0') { + // + // If any Unicode characters in Source contain + // non-zero value in the upper 8 bits, then ASSERT(). + // + ASSERT (*Source < 0x100); + *(Destination++) = (CHAR8) *(Source++); + } + + *Destination = '\0'; + + // + // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength. + // Length tests are performed inside AsciiStrLen(). + // + TempReturnValue = (Strlen((CHAR8 *)ReturnValue) + 1) * sizeof (*ReturnValue); + ASSERT (TempReturnValue!= 0); + + return ReturnValue; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeController.cif b/Core/EM/Nvme/NvmeController.cif new file mode 100644 index 0000000..b0f81a1 --- /dev/null +++ b/Core/EM/Nvme/NvmeController.cif @@ -0,0 +1,12 @@ +<component> + name = "NvmeControllerLib" + category = ModulePart + LocalRoot = "Core\EM\Nvme\" + RefName = "NvmeControllerLib" + +[files] +"NvmeController.sdl" +"NvmeController.mak" +"NvmeController.c" +"NvmeController.h" +<endComponent> diff --git a/Core/EM/Nvme/NvmeController.h b/Core/EM/Nvme/NvmeController.h new file mode 100644 index 0000000..00ebff7 --- /dev/null +++ b/Core/EM/Nvme/NvmeController.h @@ -0,0 +1,235 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeController.h 3 5/19/15 7:59a Deepthins $ +// +// $Revision: 3 $ +// +// $Date: 5/19/15 7:59a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeController.h $ +// +// 3 5/19/15 7:59a Deepthins +// [TAG] EIP218059 +// [Category] Improvement +// [Description] Update Aptio4 NVME module to spec v1.2 +// [Files] AmiNvmeController.h, NvmeController.h +// +// 2 9/04/14 7:48a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// [Files] Nvme.cif +// Nvme.mak +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// [NvmeControllerLib] +// [NvmeSmm] +// [NVMEINT13] +// [NvmeProtocol] +// +// 1 6/20/14 6:27a Anandakrishnanl +// [TAG] EIP172958 +// [Category] New Feature +// [Description] Nvme Driver Intial Checkin +// [Files] Nvme.cif +// Nvme.sdl +// Nvme.mak +// Nvme.sd +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeController.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// NvmeController.h +// +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeController.h +// +// Description: Nvme Controller related defination +// +//<AMI_FHDR_END> +//********************************************************************** + +#ifndef _NVME_CONTROLLER_H_ +#define _NVME_CONTROLLER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(1) + +// Refer to NVM Spec second 3.1 NVMe 1.1 which describes the register map for the controller +#define Offset_Cap 0x0 +#define Offset_Version 0x8 +#define Offset_Intms 0xC +#define Offset_Intmc 0x10 +#define Offset_CC 0x14 +#define Offset_CSTS 0x1C +#define CSTS_RDY 0x1 +#define CSTS_CFS 0x2 +#define Offset_Nssrs 0x20 +#define Offset_Aqa 0x24 +#define Offset_Asq 0x28 +#define Offset_Acq 0x30 +#define Offset_CMBLOC 0x38 +#define Offset_CMBSZ 0x3C +#define Offset_Admin_Submission_Queue_Tail_DoorBell 0x1000 + +// Admin Cmd Set Figure 38 NVM Express 1.1 +#define DELETE_IO_SUBMISSION_QUEUE 0x00 +#define CREATE_IO_SUBMISSION_QUEUE 0x01 +#define GET_LOG_PAGE 0x02 +#define DELETE_IO_COMPLETION_QUEUE 0x04 +#define CREATE_IO_COMPLETION_QUEUE 0x05 +#define IDENTIFY 0x06 +#define ABORT 0x08 +#define SET_FEATURES 0x09 +#define GET_FEATURES 0x0A +#define ASYNC_EVENT_REQUEST 0x0C +#define NAMESPACE_MANAGEMENT 0x0D +#define FIRMWARE_ACTIVATE 0x10 +#define FIRMWARE_IMAGE_DOWNLOAD 0x11 +#define NAMESPACE_ATTACHMENT 0x15 +#define FORMAT_NVM 0x80 +#define SECURITY_SEND 0x81 +#define SECURITY_RECEIVE 0x82 + +//Figure 149: Opcodes for NVM Commands NVM Express 1.2 +#define NVME_FLUSH 0x00 +#define NVME_WRITE 0x01 +#define NVME_READ 0x02 +#define NVME_WRITE_UNCORRECTABLE 0x04 +#define NVME_COMPARE 0x05 +#define NVME_WRITE_ZEROES 0x08 +#define NVME_DATASET_MANAGEMENT 0x09 +#define NVME_RESERVATION_REGISTER 0x0D +#define NVME_RESERVATION_REPORT 0x0E +#define NVME_RESERVATION_ACQUIRE 0x11 +#define NVME_RESERVATION_RELEASE 0x15 + + +#define QUEUE_DOORBELL_OFFSET(QUEUE_NUM, TAIL_HEAD, DoorBellStride) \ + (0x1000 + (((QUEUE_NUM * 2) + TAIL_HEAD) * (4 << DoorBellStride))) + +//MMIO Access + +#define MmAddress( BaseAddr, Register ) \ + ((UINT64)(BaseAddr) + \ + (UINTN)(Register) \ + ) +#define Mm32Ptr( BaseAddr, Register ) \ + ((volatile UINT32 *)MmAddress (BaseAddr, Register )) + +#define Mm16Ptr( BaseAddr, Register ) \ + ((volatile UINT16 *)MmAddress (BaseAddr, Register )) + +#define Mm8Ptr( BaseAddr, Register ) \ + ((volatile UINT8 *)MmAddress (BaseAddr, Register )) + +//Controller Generic Registers + +#define CONTROLLER_REG32( BaseAddr, Register ) \ + (*Mm32Ptr ((BaseAddr), (Register))) + +#define CONTROLLER_REG16( BaseAddr, Register ) \ + (*Mm16Ptr ((BaseAddr), (Register))) + +#define CONTROLLER_REG8( BaseAddr, Register ) \ + (*Mm8Ptr ((BaseAddr), (Register))) + +#define CONTROLLER_WRITE_REG32( BaseAddr, Register, Data ) \ + (CONTROLLER_REG32 ((BaseAddr), (Register))) = ((UINT32) (Data)) + +#define CONTROLLER_WRITE_REG16( BaseAddr, Register, Data ) \ + (CONTROLLER_REG16 ((BaseAddr), (Register))) = ((UINT16) (Data)) + +#define CONTROLLER_WRITE_REG8( BaseAddr, Register, Data ) \ + (CONTROLLER_REG8 ((BaseAddr), (Register))) = ((UINT8) (Data)) + +#define CONTROLLER_REG8_OR( BaseAddr, Register, OrData) \ + (CONTROLLER_REG8 ((BaseAddr), (Register))) |= ((UINT8) (OrData)) + +#define CONTROLLER_REG16_OR( BaseAddr, Register, OrData) \ + (CONTROLLER_REG16 ((BaseAddr), (Register))) |= ((UINT16) (OrData)) + +#define CONTROLLER_REG32_OR( BaseAddr, Register, OrData) \ + (CONTROLLER_REG32 ((BaseAddr), (Register))) = (CONTROLLER_REG32 ((BaseAddr), (Register))) | ((UINT32) (OrData)) + +#define CONTROLLER_REG8_AND( BaseAddr, Register, AndData) \ + (CONTROLLER_REG8 ((BaseAddr), (Register))) = (CONTROLLER_REG8 ((BaseAddr), (Register))) & ((UINT8) (AndData)) + +#define CONTROLLER_REG16_AND( BaseAddr, Register, AndData) \ + (CONTROLLER_REG16 ((BaseAddr), (Register))) &= ((UINT16) (AndData)) + +#define CONTROLLER_REG32_AND( BaseAddr, Register, AndData) \ + (CONTROLLER_REG32 ((BaseAddr), (Register))) = (CONTROLLER_REG32 ((BaseAddr), (Register))) & ((UINT32) (AndData)) + +#define CONTROLLER_REG8_AND_OR( BaseAddr, Register, AndData, OrData) \ + (CONTROLLER_REG8 ((BaseAddr), (Register)) = \ + (((CONTROLLER_REG8 ((BaseAddr), (Register))) & ((UINT8) (AndData))) | ((UINT8) (OrData)))) + +#define CONTROLLER_REG16_AND_OR( BaseAddr, Register, AndData, OrData) \ + (CONTROLLER_REG16 ((BaseAddr), (Register)) = \ + (((CONTROLLER_REG16 ((BaseAddr), (Register))) & ((UINT16) AndData)) | ((UINT16) (OrData)))) + +#define CONTROLLER_REG32_AND_OR( BaseAddr, Register,AndData, OrData) \ + (CONTROLLER_REG32 ((BaseAddr), (Register)) = \ + (((CONTROLLER_REG32 ((BaseAddr), (Register))) & ((UINT32) (AndData))) | ((UINT32) (OrData)))) + +#define AMI_NVME_CONTROLLER_PROTOCOL_GUID { 0xAFA4CF3F, 0xAF71, 0x4C30, 0xA4, 0xFB, 0x29, 0x10, 0xE7, 0x71, 0xF9, 0xB0 } +#define AMI_NVME_PASS_THRU_PROTOCOL_GUID { 0x4B215191, 0x9A25, 0x43FD, 0x86, 0xB5, 0x74, 0xE7, 0xAF, 0x72, 0x33, 0x15 } +#define AMI_NVME_LEGACY_PROTOCOL_GUID { 0xD4E79DAE, 0xAAFC, 0x4382, 0x95, 0x40, 0x3E, 0x3F, 0xA4, 0x2D, 0x42, 0x55 } +#define AMI_SMM_NVME_COMMUNICATION_GUID { 0xEC2BD1FD, 0xE3B0, 0x429B, 0xAD, 0xDF, 0x96, 0x57, 0x93, 0x5A, 0x36, 0x84 } + +CHAR8* +UnicodeStrToAsciiStr ( + IN CONST CHAR16 *Source, + OUT CHAR8 *Destination +); +#pragma pack() + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif + +#endif +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeController.mak b/Core/EM/Nvme/NvmeController.mak new file mode 100644 index 0000000..41f4d46 --- /dev/null +++ b/Core/EM/Nvme/NvmeController.mak @@ -0,0 +1,86 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* +#************************************************************************* +# $Header: /Alaska/SOURCE/Modules/NVMe/NvmeController.mak 1 9/04/14 7:45a Anandakrishnanl $ +# +# $Date: 9/04/14 7:45a $ +# +# $Log: /Alaska/SOURCE/Modules/NVMe/NvmeController.mak $ +# +# 1 9/04/14 7:45a Anandakrishnanl +# [TAG] EIP180861 +# [Category] Improvement +# [Description] Legacy Boot support in Aptio 4.x Nvme driver +# [Files] NvmeController.cif +# NvmeController.sdl +# NvmeController.mak +# NvmeController.c +# NvmeController.h +# +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/NVMe/NvmeController.mak $ +# +# 1 9/04/14 7:45a Anandakrishnanl +# [TAG] EIP180861 +# [Category] Improvement +# [Description] Legacy Boot support in Aptio 4.x Nvme driver +# [Files] NvmeController.cif +# NvmeController.sdl +# NvmeController.mak +# NvmeController.c +# NvmeController.h +# +#************************************************************************* +#<AMI_FHDR_START> +# +# Name: NvmeController.mak +# +# Description: Make file for NvmeController Lib +# +#<AMI_FHDR_END> +#********************************************************************** +all : NvmeController + +NVMECONTROLLERLIB_OBJECTS=\ +$(BUILD_DIR)\$(NVME_DIR)\NvmeController.obj\ + +$(NVMECONTROLLERLIB) : NvmeController + +NvmeController : $(BUILD_DIR)\NvmeController.mak NvmeControllerBin + +$(BUILD_DIR)\NvmeController.mak : $(NVME_DIR)\NvmeController.cif $(NVME_DIR)\NvmeController.mak $(BUILD_RULES) + $(CIF2MAK) $(NVME_DIR)\NvmeController.cif $(CIF2MAK_DEFAULTS) + +NvmeControllerBin : + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\NvmeController.mak all\ + MAKEFILE=$(NVME_DIR)\NvmeController.mak\ + "OBJECTS=$(NVMECONTROLLERLIB_OBJECTS)"\ + "EXT_HEADERS=$(BUILD_DIR)\token.h"\ + TYPE=LIBRARY LIBRARY_NAME=$(NVMECONTROLLERLIB) +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/Core/EM/Nvme/NvmeController.sdl b/Core/EM/Nvme/NvmeController.sdl new file mode 100644 index 0000000..49891ee --- /dev/null +++ b/Core/EM/Nvme/NvmeController.sdl @@ -0,0 +1,31 @@ +TOKEN + Name = "NvmeController_SUPPORT" + Value = "1" + Help = "Main switch to enable NVMe Controller Library support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes + Master = Yes +End + +PATH + Name = "NVME_DIR" +End + +MODULE + Help = "Includes NvmeController.mak to Project" + File = "NvmeController.mak" +End + +ELINK + Name = "NVMECONTROLLERLIB" + InvokeOrder = ReplaceParent +End + +ELINK + Name = "$(BUILD_DIR)\NvmeController.lib" + Parent = "NVMECONTROLLERLIB" + InvokeOrder = AfterParent +End + + diff --git a/Core/EM/Nvme/NvmeIncludes.h b/Core/EM/Nvme/NvmeIncludes.h new file mode 100644 index 0000000..acb4464 --- /dev/null +++ b/Core/EM/Nvme/NvmeIncludes.h @@ -0,0 +1,120 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeIncludes.h 2 9/04/14 7:37a Anandakrishnanl $ +// +// $Revision: 2 $ +// +// $Date: 9/04/14 7:37a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeIncludes.h $ +// +// 2 9/04/14 7:37a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// +// [Files] +// Nvme.cif +// Nvme.mak +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// [NvmeControllerLib] +// [NvmeSmm] +// [NVMEINT13] +// [NvmeProtocol] +// +// 1 6/20/14 6:27a Anandakrishnanl +// [TAG] EIP172958 +// [Category] New Feature +// [Description] Nvme Driver Intial Checkin +// [Files] Nvme.cif +// Nvme.sdl +// Nvme.mak +// Nvme.sd +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeController.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// NvmeController.h +// +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeIncludes.h +// +// Description: Common header file for the Nvme Driver +// +//<AMI_FHDR_END> +//********************************************************************** + +#ifndef _NVME_INCLUDES_H_ +#define _NVME_INCLUDES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <Token.h> + +#include <Efi.h> +#include <AmiLib.h> +#include <Pci.h> +#include <Protocol/PciIo.h> +#include <Protocol/DriverBinding.h> +#include <Protocol/BlockIo.h> +#include <Protocol/PDiskInfo.h> +#include <Protocol/ComponentName2.h> +#include <Protocol/SmmBase.h> +#include <Protocol/SmmControl2.h> +#include <Protocol/SmmCommunication.h> +#include "NvmeInt13/NvmeInt13.h" + + +#define LANGUAGE_CODE_ENGLISH "en-US" +#define MSG_NVME_DP 23 + + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif + +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeInt13/NvmeInt13.c b/Core/EM/Nvme/NvmeInt13/NvmeInt13.c new file mode 100644 index 0000000..b58c1f0 --- /dev/null +++ b/Core/EM/Nvme/NvmeInt13/NvmeInt13.c @@ -0,0 +1,474 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeInt13/NvmeInt13.c 2 2/02/16 1:31a Karthikar $ +// +// $Revision: 2 $ +// +// $Date: 2/02/16 1:31a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeInt13/NvmeInt13.c $ +// +// 2 2/02/16 1:31a Karthikar +// [TAG] EIP254245 +// [Category] Bug Fix +// [Symptom] Static code analysis issues found in Aptio4 Nvme module +// [RootCause] In for loop comma operator is used instead of && for +// mutiple test conditions. +// [Solution] Replaced comma operator with &&. +// [Files] NvmeInt13.c +// +// 1 9/04/14 7:56a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// [Files] NvmeInt13.cif +// NvmeInt13.c +// NvmeInt13.h +// NvmeInt13.sdl +// NvmeInt13.mak +// NvmeInt13.inf +// NvmeInt13.dxs +// +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeInt13.c +// +// Description: Nvme Driver for Legacy Mode. It installs the Int13 +// support for the Nvme devices +// +//<AMI_FHDR_END> +//********************************************************************** + +#include "Token.h" +#include "AmiDxeLib.h" +#include "NvmeInt13.h" +#include <Protocol/ComponentName.h> +#include <Protocol/LegacyBiosExt.h> +#include <Protocol/LegacyBios.h> +#include <Protocol/PciIo.h> +#include <Protocol/BlockIo.h> + +EFI_LEGACY_BIOS_EXT_PROTOCOL *gBiosExtensions = NULL; +NVME_INT13_DATA *gNvmeInt13BinData = NULL; +AMI_NVME_LEGACY_PROTOCOL gNvmeLegacyProtocol; + +static EFI_GUID gAmiNvmeLegacyProtocolGuid = AMI_NVME_LEGACY_PROTOCOL_GUID; + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeInt13EntryPoint +// +// Description: NVMe INT13 driver entry point. Installs call back +// notification on gAmiNvmeLegacyProtocolGuid installation. +// +// Input: +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: None +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeInt13EntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + EFI_HANDLE NvmeInt13Handle=NULL; + + InitAmiLib(ImageHandle, SystemTable); + + Status = InitInt13RuntimeImage(); + if (EFI_ERROR(Status)) { + return Status; + } + + gNvmeLegacyProtocol.AddNvmeLegacyDevice = NvmeInstallLegacyDevice; + + Status = pBS->InstallProtocolInterface ( + &NvmeInt13Handle, + &gAmiNvmeLegacyProtocolGuid, + EFI_NATIVE_INTERFACE, + &gNvmeLegacyProtocol + ); + + return Status; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: InitInt13RuntimeImage +// +// Description: Initialization of data structures and placement of runtime +// +// Input: +// NONE +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: None +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +InitInt13RuntimeImage() +{ + EFI_STATUS Status; + VOID *Image; + UINTN ImageSize = 0; + + + // + // Get the NVMe INT13 runtime image + // + Status = pBS->LocateProtocol( + &gEfiLegacyBiosExtProtocolGuid, NULL, &gBiosExtensions); + if (EFI_ERROR(Status)) return Status; + + Status = gBiosExtensions->GetEmbeddedRom( + CSM16_MODULEID, CSM16_VENDORID, CSM16_NVME_RT_DID, &Image, &ImageSize); + if (EFI_ERROR(Status)) return Status; + + // + // Do the necessary RT data initialization here using Image before it is shadowed + //.............................. + { +#pragma pack(push, 1) + // Update NVMe SMI information + typedef struct _NVME_SMM_RTS { + UINT8 MiscInfo; + UINT16 SmmAttr; + UINT32 SmmPort; + UINT32 SmmData; + } NVME_SMM_RTS; + + static NVME_SMM_RTS NvmeSmmRt = {1, 0, SW_SMI_IO_ADDRESS, NVME_SWSMI}; + + *(NVME_SMM_RTS*)((UINTN)Image + ((NVME_INT13_DATA*)Image)->NvmeSmmDataOffset) = NvmeSmmRt; +#pragma pack(pop) + } + + // Copy image to shadow E000/F000 area + (UINTN)gNvmeInt13BinData = gBiosExtensions->CopyLegacyTable(Image, (UINT16)ImageSize, 0x10, 2); + + TRACE((-1, "gNvmeInt13BinData : %lX\n", gNvmeInt13BinData)); + + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: CreateDeviceName +// +// Description: This function retrieves NVMe device name, copies it into +// lower memory and returns a pointer to the string +// +// Input: +// UINT8 DevIndex, +// UINT8 *DevNameStringSrc, +// UINT16 *StringDestinationSegment, +// UINT16 *StringDestinationOffset, +// UINT16 *MfgStringDestinationSegment, +// UINT16 *MfgStringDestinationOffset +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: None +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +CreateDeviceName ( + UINT8 DevIndex, + UINT8 *DevNameStringSrc, + UINT16 *StringDestinationSegment, + UINT16 *StringDestinationOffset, + UINT16 *MfgStringDestinationSegment, + UINT16 *MfgStringDestinationOffset +) +{ + UINT8 *DevName = (gNvmeInt13BinData->NvmeMassI13Dev)[DevIndex].DeviceNameString; + UINT8 i; + + // + // Copy the string, compact it on the way (no more that one ' ' in a row) + // + for (i=0; i<31 && *DevNameStringSrc != 0; i++, DevNameStringSrc++) + { + if ((*DevNameStringSrc == 0x20) && (*(DevNameStringSrc-1) == 0x20)) continue; + *DevName++ = *DevNameStringSrc; // DevNameStringSrc incremented unconditionally + } + *DevName = 0; // string terminator + + DevName = (gNvmeInt13BinData->NvmeMassI13Dev)[DevIndex].DeviceNameString; + + *StringDestinationSegment = (UINT16)(((UINTN)DevName & 0xf0000) >> 4); + *StringDestinationOffset = (UINT16)((UINTN)DevName & 0xffff); + + *MfgStringDestinationSegment = (UINT16)(((UINTN)gNvmeInt13BinData->MfgGenericName & 0xf0000) >> 4); + *MfgStringDestinationOffset = (UINT16)((UINTN)gNvmeInt13BinData->MfgGenericName & 0xffff); + + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: CreateBbsEntry +// +// Description: This function takes the device index within NVMEMASS_INT13_DEV +// list and prepares BBS entry for this device +// +// Input: +// UINT8 DevIndex, +// IN NVME_LEGACY_MASS_DEVICE *NvmeLegacyMassDevice, +// OUT BBS_TABLE *BbsEntry +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: None +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +CreateBbsEntry ( + UINT8 DevIndex, + IN NVME_LEGACY_MASS_DEVICE *NvmeLegacyMassDevice, + OUT BBS_TABLE *BbsEntry +) +{ + EFI_STATUS Status; + UINT8 Handle; + UINT8 DevAndSysType; + UINT8 BaidDeviceType; + BBS_STATUS_FLAGS StatusFlags; + + ASSERT(DevIndex < NVMEDEVS_MAX_ENTRIES); + + if (gBiosExtensions == NULL) { + return EFI_NOT_FOUND; + } + + pBS->SetMem(BbsEntry, sizeof(BBS_TABLE), 0); + + // + // Get the HC PCI location + // + BbsEntry->Bus = (UINT32)(NvmeLegacyMassDevice->PciBDF >> 8); + BbsEntry->Device = (UINT32)((NvmeLegacyMassDevice->PciBDF & 0xFF) >> 3); + BbsEntry->Function = (UINT32)(NvmeLegacyMassDevice->PciBDF & 7); + + // + // Update class/subclass information + // + BbsEntry->Class = PCI_CLASS_MASS_STORAGE; + BbsEntry->SubClass = PCI_CLASS_MASS_STORAGE_SOLID_STATE; + + StatusFlags.Enabled = 1; StatusFlags.MediaPresent = 1; + BbsEntry->StatusFlags = StatusFlags; // Enabled, Unknown media + + // + // Copy the device name string into low memory at gLegacyMemoryAddress, and + // update the string pointer in BBS table entry + // + Status = CreateDeviceName( + DevIndex, + NvmeLegacyMassDevice->DevString, + &BbsEntry->DescStringSegment, + &BbsEntry->DescStringOffset, + &BbsEntry->MfgStringSegment, + &BbsEntry->MfgStringOffset + ); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return Status; + + DevAndSysType = (SYSTYPE_ATA << 4)+DEVTYPE_SYS; + Handle = (UINT8)NvmeLegacyMassDevice->LogicalAddress; + + switch (NvmeLegacyMassDevice->StorageType) { + + case NVME_MASS_DEV_HDD: + BbsEntry->DeviceType = BBS_HARDDISK; + BaidDeviceType = BAID_TYPE_HDD; + Handle |= 0x80; + BbsEntry->BootHandlerSegment = (UINT16)((UINTN)gNvmeInt13BinData >> 4); + BbsEntry->BootHandlerOffset = gNvmeInt13BinData->BcvOffset + DevIndex*4; + break; + + default: + BbsEntry->DeviceType = BBS_UNKNOWN; + } + + BbsEntry->InitPerReserved = ((UINT32)BaidDeviceType<<24) + +((UINT32)Handle<<8) + +(UINT32)DevAndSysType; + + *(UINTN*)(&BbsEntry->IBV1) = (UINTN)NvmeLegacyMassDevice->Handle; + + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: NvmeInstallLegacyDevice +// +// Description: This API is called by NVMe bus driver. The device is added into CSM16 +// data area for legacy boot +// +// Input: +// NVME_LEGACY_MASS_DEVICE *NvmeLegacyMassDevice +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: None +// +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +NvmeInstallLegacyDevice ( + NVME_LEGACY_MASS_DEVICE *NvmeLegacyMassDevice +) +{ + BBS_TABLE BbsEntry; + EFI_STATUS Status; + UINT8 EntryNumber = 0xff; + UINT8 Index; + NVME_MASS_DEV_INFO *Device; + NVME_DEV_PCI_LOCATION *NvmePciDataOffset; + + TRACE((-1, "Installing NVMe INT13 device %lx\n", NvmeLegacyMassDevice)); + + // + // See if device is already in the list, if yes - return error. + // + for (Index = 0; Index < NVMEDEVS_MAX_ENTRIES; Index++) { + if ((gNvmeInt13BinData->NvmeMassI13Dev)[Index].Handle == (UINT8)NvmeLegacyMassDevice->LogicalAddress) { + ASSERT(FALSE); // ERROR: Device already exists + return EFI_INVALID_PARAMETER; + } + } + // + // Look for an empty slot in BcvLookupTable + // + for (Index=0; Index<NVMEDEVS_MAX_ENTRIES; Index++) { + if ((gNvmeInt13BinData->NvmeMassI13Dev)[Index].Handle == 0) { + break; + } + } + + ASSERT(Index<NVMEDEVS_MAX_ENTRIES); + + if (Index==NVMEDEVS_MAX_ENTRIES) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gBiosExtensions->UnlockShadow(0, 0, 0, 0); + ASSERT_EFI_ERROR(Status); + + Status = CreateBbsEntry(Index, NvmeLegacyMassDevice, &BbsEntry); + ASSERT_EFI_ERROR(Status); + + Status = gBiosExtensions->InsertBbsEntryAt(gBiosExtensions, + &BbsEntry, + &EntryNumber); + ASSERT_EFI_ERROR(Status); + + // + // Entry has been successfully added, update the lookup table + // + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].Handle = (UINT8)NvmeLegacyMassDevice->LogicalAddress; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].BbsEntryNo = EntryNumber; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].DevBaidType = (UINT8)(BbsEntry.InitPerReserved>>24); + + // + // Update device geometry related information + // + Device = (NVME_MASS_DEV_INFO*)NvmeLegacyMassDevice->DevInfo; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].NumHeads = Device->bNonLBAHeads; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].LBANumHeads = Device->bHeads; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].NumCylinders = Device->wNonLBACylinders; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].LBANumCyls = Device->wCylinders; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].NumSectors = Device->bNonLBASectors; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].LBANumSectors = Device->bSectors; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].BytesPerSector = Device->wBlockSize; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].LastLBA = Device->dMaxLba; + (gNvmeInt13BinData->NvmeMassI13Dev)[Index].BpbMediaDesc = 0; + + // Update PCI Bus# + NvmePciDataOffset = (NVME_DEV_PCI_LOCATION *)((UINTN)gNvmeInt13BinData + gNvmeInt13BinData->NvmePciDataOffset); + NvmePciDataOffset[Index].Handle = (UINT8)NvmeLegacyMassDevice->LogicalAddress; + NvmePciDataOffset[Index].PciBDF = NvmeLegacyMassDevice->PciBDF; + + Status = gBiosExtensions->LockShadow(0, 0); + ASSERT_EFI_ERROR(Status); + + return EFI_SUCCESS; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeInt13/NvmeInt13.cif b/Core/EM/Nvme/NvmeInt13/NvmeInt13.cif new file mode 100644 index 0000000..e2c2bb6 --- /dev/null +++ b/Core/EM/Nvme/NvmeInt13/NvmeInt13.cif @@ -0,0 +1,16 @@ +<component> + name = "Nvme Int13" + category = ModulePart + LocalRoot = "Core\EM\Nvme\NvmeInt13\" + RefName = "NVMEINT13" + +[files] +"NvmeInt13.c" +"NvmeInt13.h" +"NvmeInt13.sdl" +"NvmeInt13.mak" +"NvmeInt13.inf" +"NvmeInt13.dxs" +[parts] +"NVME_I13_BINARY" +<endComponent> diff --git a/Core/EM/Nvme/NvmeInt13/NvmeInt13.dxs b/Core/EM/Nvme/NvmeInt13/NvmeInt13.dxs new file mode 100644 index 0000000..ae03d50 --- /dev/null +++ b/Core/EM/Nvme/NvmeInt13/NvmeInt13.dxs @@ -0,0 +1,71 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeInt13/NvmeInt13.dxs 1 9/04/14 7:56a Anandakrishnanl $ +// +// $Revision: 1 $ +// +// $Date: 9/04/14 7:56a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeInt13/NvmeInt13.dxs $ +// +// 1 9/04/14 7:56a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// [Files] NvmeInt13.cif +// NvmeInt13.c +// NvmeInt13.h +// NvmeInt13.sdl +// NvmeInt13.mak +// NvmeInt13.inf +// NvmeInt13.dxs +// +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeInt13.dxs +// +// Description: This file is the dependency file for the NvmeInt13 driver +// +//<AMI_FHDR_END> +//********************************************************************** +#include "token.h" +#ifdef CSM_SUPPORT +#include <Protocol\LegacyBiosExt.h> +#include <Protocol/LegacyBios.h> +#endif + +DEPENDENCY_START +#if CSM_SUPPORT + EFI_LEGACY_BIOS_EXT_PROTOCOL_GUID AND + EFI_LEGACY_BIOS_PROTOCOL_GUID +#endif +DEPENDENCY_END + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/Nvme/NvmeInt13/NvmeInt13.h b/Core/EM/Nvme/NvmeInt13/NvmeInt13.h new file mode 100644 index 0000000..c8d48a0 --- /dev/null +++ b/Core/EM/Nvme/NvmeInt13/NvmeInt13.h @@ -0,0 +1,161 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeInt13/NvmeInt13.h 1 9/04/14 7:56a Anandakrishnanl $ +// +// $Revision: 1 $ +// +// $Date: 9/04/14 7:56a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeInt13/NvmeInt13.h $ +// +// 1 9/04/14 7:56a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// [Files] NvmeInt13.cif +// NvmeInt13.c +// NvmeInt13.h +// NvmeInt13.sdl +// NvmeInt13.mak +// NvmeInt13.inf +// NvmeInt13.dxs +// +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeInt13.h +// +// Description: Definitions and structures for NVMe INT13 +// +//<AMI_FHDR_END> +//********************************************************************** + +#ifndef __NVMEI13_H__ +#define __NVMEI13_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <Efi.h> +#include <Protocol/AmiNvmeLegacy.h> +#include "NvmeBus.h" + +#define BAID_TYPE_HDD 1 +#define BAID_TYPE_RMD_HDD 2 +#define BAID_TYPE_CDROM 3 +#define BAID_TYPE_RMD_FDD 4 +#define BAID_TYPE_FDD 5 + +#define CSM16_NVME_RT_DID 5 + +#define SYSTYPE_ATA 0 +#define DEVTYPE_SYS 1 + +// Values for Mass Storage Device type +//------------------------------------- +#define NVME_MASS_DEV_HDD 1 +#define MAX_NVME_DEVICES 16 +#define NVMEDEVS_MAX_ENTRIES 8 + +#pragma pack(1) + +typedef struct _NVME_MASS_DEV_INFO{ + UINT16 wBlockSize; + UINT64 dMaxLba; + UINT8 bHeads; + UINT8 bSectors; + UINT16 wCylinders; + UINT8 bNonLBAHeads; + UINT8 bNonLBASectors; + UINT16 wNonLBACylinders; +} NVME_MASS_DEV_INFO; + +struct _NVME_LEGACY_MASS_DEVICE { + VOID *DevInfo; + UINT16 LogicalAddress; + EFI_HANDLE Handle; + UINT16 PciBDF; + UINT8 *DevString; + UINT8 StorageType; +}; + +typedef struct { + UINT8 Handle; + UINT16 PciBDF; +} NVME_DEV_PCI_LOCATION; + + +typedef struct { + UINT8 Handle; + UINT8 BbsEntryNo; + UINT8 DevBaidType; + UINT8 NumHeads; + UINT8 LBANumHeads; + UINT16 NumCylinders; + UINT16 LBANumCyls; + UINT8 NumSectors; + UINT8 LBANumSectors; + UINT16 BytesPerSector; + UINT8 MediaType; + UINT64 LastLBA; + UINT8 BpbMediaDesc; + UINT8 DeviceNameString[32]; +} NVMEMASS_INT13_DEV; + +// +// The following data structure is located in NvmeI13.BIN +// +typedef struct { + NVMEMASS_INT13_DEV NvmeMassI13Dev[NVMEDEVS_MAX_ENTRIES]; + UINT8 MfgGenericName[13]; // "NVME Storage", 0 + UINT16 BcvOffset; + UINT16 NvmeSmmDataOffset; + UINT16 NvmePciDataOffset; +} NVME_INT13_DATA; + +#pragma pack() + +EFI_STATUS +NvmeInstallLegacyDevice ( + NVME_LEGACY_MASS_DEVICE *NvmeLegacyMassDevice +); + +EFI_STATUS +InitInt13RuntimeImage(); + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif + +#endif + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeInt13/NvmeInt13.inf b/Core/EM/Nvme/NvmeInt13/NvmeInt13.inf new file mode 100644 index 0000000..3a75d3d --- /dev/null +++ b/Core/EM/Nvme/NvmeInt13/NvmeInt13.inf @@ -0,0 +1,5 @@ +[MODULE] +ModuleID = 1 +VendorID = 0 +DeviceID = 5 +File = Addon\NvmeI13.BIN diff --git a/Core/EM/Nvme/NvmeInt13/NvmeInt13.mak b/Core/EM/Nvme/NvmeInt13/NvmeInt13.mak new file mode 100644 index 0000000..54c9372 --- /dev/null +++ b/Core/EM/Nvme/NvmeInt13/NvmeInt13.mak @@ -0,0 +1,84 @@ +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** +#********************************************************************** +# $Header: /Alaska/SOURCE/Modules/NVMe/NvmeInt13/NvmeInt13.mak 1 9/04/14 7:56a Anandakrishnanl $ +# +# $Revision: 1 $ +# +# $Date: 9/04/14 7:56a $ +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/NVMe/NvmeInt13/NvmeInt13.mak $ +# +# 1 9/04/14 7:56a Anandakrishnanl +# [TAG] EIP180861 +# [Category] Improvement +# [Description] Legacy Boot support in Aptio 4.x Nvme driver +# [Files] NvmeInt13.cif +# NvmeInt13.c +# NvmeInt13.h +# NvmeInt13.sdl +# NvmeInt13.mak +# NvmeInt13.inf +# NvmeInt13.dxs +# +#********************************************************************** +#********************************************************************** +#<AMI_FHDR_START> +# +# Name: NvmeInt13.mak +# +# Description: Make file for NvmeInt13 +# +#<AMI_FHDR_END> +#********************************************************************** + +all: NVMEINT13 + +$(BUILD_DIR)\NvmeInt13.mak: $(NVME_INT13_DIR)\NvmeInt13.cif $(NVME_INT13_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(CIF2MAK_DEFAULTS) $(NVME_INT13_DIR)\NvmeInt13.cif + +NVMEINT13: $(BUILD_DIR)\NvmeInt13.mak NVMEINT13BIN + +NVME_INT13_INCLUDES=\ + /I$(NVME_DIR)\ + +NVME_OBJECTS = \ +$(BUILD_DIR)\$(NVME_INT13_DIR)\NvmeInt13.obj \ + +NVMEINT13BIN: $(AMIDXELIB) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\NvmeInt13.mak all\ + GUID=C9A6DE36-FDFF-4FAF-8343-85D9E3470F43\ + "OBJECTS=$(NVME_OBJECTS)"\ + "MY_INCLUDES=$(NVME_INT13_INCLUDES)"\ + ENTRY_POINT=NvmeInt13EntryPoint\ + TYPE=BS_DRIVER\ + COMPRESS=1\ + DEPEX1=$(NVME_INT13_DIR)\NvmeInt13.dxs \ + +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** diff --git a/Core/EM/Nvme/NvmeInt13/NvmeInt13.sdl b/Core/EM/Nvme/NvmeInt13/NvmeInt13.sdl new file mode 100644 index 0000000..b4c6cb1 --- /dev/null +++ b/Core/EM/Nvme/NvmeInt13/NvmeInt13.sdl @@ -0,0 +1,48 @@ +TOKEN + Name = "NVMEINT13_SUPPORT" + Value = "1" + Help = "Main switch to enable Sdio Int13 support in the project." + TokenType = Boolean + TargetMAK = Yes + TargetH = Yes + Master = Yes + Token = "CSM_SUPPORT" "=" "1" +End + +PATH + Name = "NVME_INT13_DIR" + Path = "Core\EM\Nvme\NvmeInt13" +End + +MODULE + Help = "Includes NvmeInt13.mak" + File = "NvmeInt13.mak" +End + +TOKEN + Name = "NVME_SWSMI" + Value = "0x42" + Help = "Data to be written to SW SMI port to invoke NVME SW SMI handler." + TokenType = Integer + TargetH = Yes +End + +ELINK + Name = "$(BUILD_DIR)\NvmeInt13.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + + +TOKEN + Name = "NVMEI13_BIN" + Value = "addon\NvmeI13.bin" + TokenType = Expression + TargetMAK = Yes +End + +ELINK + Name = "$(NVME_INT13_DIR)\NvmeInt13.inf" + Parent = "CSM_CUSTOM_INFS" + InvokeOrder = AfterParent +End diff --git a/Core/EM/Nvme/NvmePassthru.c b/Core/EM/Nvme/NvmePassthru.c new file mode 100644 index 0000000..837de1d --- /dev/null +++ b/Core/EM/Nvme/NvmePassthru.c @@ -0,0 +1,619 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (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/NvmePassthru.c 1 5/14/15 2:36a Karthikar $ +// +// $Revision: 1 $ +// +// $Date: 5/14/15 2:36a $ +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmePassthru.c +// +// Description: Contain Nvme Express passthru protocol APIs definition +// +//<AMI_FHDR_END> +//********************************************************************** + +#include "NvmeIncludes.h" +#include "NvmeController.h" +#include "NvmeBus.h" +#include "Protocol/AmiNvmeController.h" +#include "NvmePassthru.h" +#include <Protocol\DevicePath.h> +#include <Protocol\BlockIo.h> + +// Global Declaration +EFI_BOOT_SERVICES *pBS; + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: GetActiveNameSpace +// +// Description: +// Routine to get the Active NameSpace +// +// Input: +// IN AMI_NVME_CONTROLLER_PROTOCOL *NvmeController +// IN UINT32 NamespaceId +// Output: +// ACTIVE_NAMESPACE_DATA pointer for the NamespaceId +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +ACTIVE_NAMESPACE_DATA* +GetActiveNameSpace ( + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController, + UINT32 NamespaceId +) +{ + LIST_ENTRY *LinkData; + ACTIVE_NAMESPACE_DATA *ActiveNameSpace = NULL; + + if(!NvmeController) { + return NULL; + } + + for (LinkData = NvmeController->ActiveNameSpaceList.ForwardLink; + LinkData != &NvmeController->ActiveNameSpaceList; + LinkData = LinkData->ForwardLink) { + + ActiveNameSpace = _CR(LinkData, ACTIVE_NAMESPACE_DATA, Link); + + if(ActiveNameSpace->ActiveNameSpaceID == NamespaceId) { + return ActiveNameSpace; + } + } + return NULL; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: NvmePassThru +// +// Description: +// Sends an NVM Express Command Packet to an NVM Express controller or namespace +// +// Input: +// IN This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance +// IN NamespaceId A 32 bit namespace ID as defined in the NVMe specification +// to which the NVM Express Command Packet will be sent. +// IN Packet A pointer to the NVM Express Command Packet to send to +// the NVMe namespace specified by NamespaceId. +// IN Event Event to be signaled when the NVM Express Command Packet completes +// and non-blocking I/O is supported +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +NvmePassThru ( + IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, + IN UINT32 NamespaceId, + IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event +) +{ + EFI_STATUS Status; + ACTIVE_NAMESPACE_DATA *ActiveNameSpace = NULL; + NVME_COMMAND_WRAPPER *NvmeCmdWrapper = NULL; + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController; + UINT32 AlignmentBoundry; + VOID *BufferUnMap = NULL; + COMPLETION_QUEUE_ENTRY *NvmeCompletionData = NULL; + UINT8 NvmeOpcode; + UINT64 LBA; + + if( !This || !Packet || !Packet->NvmeCmd ) { + return EFI_INVALID_PARAMETER; + } + + NvmeOpcode = Packet->NvmeCmd->Cdw0.OpCode; + + // Return if QueueType is invalid + if (Packet->QueueType != NVME_ADMIN_SUBMISSION_QUEUE && Packet->QueueType != NVME_IO_SUBMISSION_QUEUE) { + return EFI_INVALID_PARAMETER; + } + + // Check Transfer buffer is NULL, if not,Check its memory is properly alligned or not + if( Packet->TransferBuffer && ( This->Mode->IoAlign > 1 ) ) { + + // Should be align in 2's power + AlignmentBoundry = 1 << This->Mode->IoAlign; + // + //Get what is the number in 2 to the power Mode->IoAlign + // + if((0 != ((UINTN)((UINTN)(Packet->TransferBuffer) % AlignmentBoundry) ) || + (0 != ((UINTN)( Packet->TransferLength % AlignmentBoundry))) )) { + return EFI_INVALID_PARAMETER; + } + } + + NvmeController = NVME_CONTROLLER_PROTOCOL_FROM_THIS(This); + + if(!Packet->NvmeCompletion) { + return EFI_INVALID_PARAMETER; + } + + NvmeCompletionData = (COMPLETION_QUEUE_ENTRY*)Packet->NvmeCompletion; + + Status = pBS->AllocatePool ( + EfiBootServicesData, + sizeof(NVME_COMMAND_WRAPPER), + (VOID**)&NvmeCmdWrapper + ); + + if (EFI_ERROR(Status)) { + return Status; + } + // Clear memory + pBS->SetMem(NvmeCmdWrapper, sizeof(NVME_COMMAND_WRAPPER), 0); + + // Fill Common values of command + NvmeCmdWrapper->NvmCmd.CMD0.Opcode = NvmeOpcode; + (UINT8)NvmeCmdWrapper->NvmCmd.CMD0.FusedOperation = Packet->NvmeCmd->Cdw0.FusedOperation; + NvmeCmdWrapper->NvmCmd.CMD0.CommandIdentifier = Packet->QueueType? NvmeController->CommandIdentifierQueue1 : NvmeController->CommandIdentifierAdmin; + NvmeCmdWrapper->NvmCmd.NSID = Packet->NvmeCmd->Nsid; + NvmeCmdWrapper->NvmCmd.MPTR = 0; + NvmeCmdWrapper->AdminOrNVMCmdSet = Packet->QueueType ? FALSE : TRUE; + NvmeCmdWrapper->SQIdentifier = Packet->QueueType; // Queue 0 for Admin cmds,1 for I/O command + NvmeCmdWrapper->CmdTimeOut = (UINT32)Packet->CommandTimeout; + + if(Packet->NvmeCmd->Flags & CDW10_VALID) { + NvmeCmdWrapper->NvmCmd.CDW10 = Packet->NvmeCmd->Cdw10; + } + if(Packet->NvmeCmd->Flags & CDW11_VALID) { + NvmeCmdWrapper->NvmCmd.CDW11 = Packet->NvmeCmd->Cdw11; + } + if(Packet->NvmeCmd->Flags & CDW12_VALID) { + NvmeCmdWrapper->NvmCmd.CDW12 = Packet->NvmeCmd->Cdw12; + } + if(Packet->NvmeCmd->Flags & CDW13_VALID) { + NvmeCmdWrapper->NvmCmd.CDW13 = Packet->NvmeCmd->Cdw13; + } + if(Packet->NvmeCmd->Flags & CDW14_VALID) { + NvmeCmdWrapper->NvmCmd.CDW14 = Packet->NvmeCmd->Cdw14; + } + if(Packet->NvmeCmd->Flags & CDW15_VALID) { + NvmeCmdWrapper->NvmCmd.CDW15 = Packet->NvmeCmd->Cdw15; + } + + // if QueueType is 0, Admin Command + // if QueueType is 1, I/O Command + if ( Packet->QueueType == NVME_ADMIN_SUBMISSION_QUEUE ) { + + Status = EFI_SUCCESS; + switch(NvmeOpcode) + { + case DELETE_IO_SUBMISSION_QUEUE: + case CREATE_IO_SUBMISSION_QUEUE: + case DELETE_IO_COMPLETION_QUEUE: + case CREATE_IO_COMPLETION_QUEUE: + case ABORT: + case ASYNC_EVENT_REQUEST: + Status = EFI_UNSUPPORTED; + break; + case IDENTIFY: + + if( !( (Packet->NvmeCmd->Flags & CDW10_VALID) && Packet->TransferBuffer ) ) { + Status = EFI_INVALID_PARAMETER; + goto PassthruErrorExit; + } + + if( Packet->TransferLength < sizeof(IDENTIFY_CONTROLLER_DATA) ) { + Status = EFI_BAD_BUFFER_SIZE; + goto PassthruErrorExit; + } + + NvmeCmdWrapper->NvmCmd.PRP1 = (UINT64)Packet->TransferBuffer; + + // If PRP1 isn't aligned on MemoryPageSize, then PRP2 will also be used. + NvmeCmdWrapper->NvmCmd.PRP2 = ((UINT64)Packet->TransferBuffer & ~((UINT64)NvmeController->MemoryPageSize-1)) + + NvmeController->MemoryPageSize; + break; + + case GET_FEATURES: + case SET_FEATURES: + if( (Packet->NvmeCmd->Flags & (CDW10_VALID | CDW11_VALID)) != (CDW10_VALID | CDW11_VALID)) { + Status = EFI_INVALID_PARAMETER; + goto PassthruErrorExit; + } + if( Packet->TransferBuffer ) { + NvmeCmdWrapper->NvmCmd.PRP1 = (UINT64)Packet->TransferBuffer; + + // If PRP1 isn't aligned on MemoryPageSize, then PRP2 will also be used. + NvmeCmdWrapper->NvmCmd.PRP2 = ((UINT64)Packet->TransferBuffer & ~((UINT64)NvmeController->MemoryPageSize-1)) + + NvmeController->MemoryPageSize; + } + break; + + case GET_LOG_PAGE: + if( !( (Packet->NvmeCmd->Flags & CDW10_VALID) && Packet->TransferBuffer) ) { + Status = EFI_INVALID_PARAMETER; + goto PassthruErrorExit; + } + + NvmeCmdWrapper->NvmCmd.PRP1 = (UINT64)Packet->TransferBuffer; + + // If PRP1 isn't aligned on MemoryPageSize, then PRP2 will also be used. + NvmeCmdWrapper->NvmCmd.PRP2 = ((UINT64)Packet->TransferBuffer & ~((UINT64)NvmeController->MemoryPageSize-1)) + + NvmeController->MemoryPageSize; + break; + + case FORMAT_NVM: + if( !(Packet->NvmeCmd->Flags & CDW10_VALID) ) { + Status = EFI_INVALID_PARAMETER; + goto PassthruErrorExit; + } + break; + + case SECURITY_SEND: + case SECURITY_RECEIVE: + if( ( (Packet->NvmeCmd->Flags & (CDW10_VALID | CDW11_VALID)) != (CDW10_VALID | CDW11_VALID)) ) { + Status = EFI_INVALID_PARAMETER; + goto PassthruErrorExit; + } + + NvmeCmdWrapper->NvmCmd.PRP1 = (UINT64)Packet->TransferBuffer; + + // If PRP1 isn't aligned on MemoryPageSize, then PRP2 will also be used. + NvmeCmdWrapper->NvmCmd.PRP2 = ((UINT64)Packet->TransferBuffer & ~((UINT64)NvmeController->MemoryPageSize-1)) + + NvmeController->MemoryPageSize; + break; + + case FIRMWARE_ACTIVATE: + case FIRMWARE_IMAGE_DOWNLOAD: + default: + Status = EFI_UNSUPPORTED; + break; + } + if( Status != EFI_UNSUPPORTED ) { + // Send Nvme Command + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, (COMPLETION_QUEUE_ENTRY*)NvmeCompletionData); + } + } else { // Send NVM command to Valid Namespace ID + + Status = EFI_INVALID_PARAMETER; + switch(NvmeOpcode) + { + case NVME_READ: + case NVME_WRITE: + case NVME_COMPARE: + + // LBA value is passed through Command Dword 10 & 11, return error if either CDW10 or CDW11 is invalid + if( ((Packet->NvmeCmd->Flags & (CDW10_VALID | CDW11_VALID)) != (CDW10_VALID | CDW11_VALID)) ) { + break; + } + + LBA = Packet->NvmeCmd->Cdw11; + LBA = Shl64(LBA, 32) | ( (UINT64)Packet->NvmeCmd->Cdw10 & 0x0FFFFFFFF ); + + ActiveNameSpace = GetActiveNameSpace( NvmeController, Packet->NvmeCmd->Nsid ); + + if( !ActiveNameSpace ) { + goto PassthruErrorExit; + } + Status = NvmeReadWriteBlocks ( ActiveNameSpace, + 0, // MediaId = 0 + LBA, + (UINT64)Packet->TransferLength, // BufferSize, + (VOID*)(Packet->TransferBuffer), // Buffer, + (COMPLETION_QUEUE_ENTRY*)NvmeCompletionData, + NvmeOpcode // ReadWriteOpCode + ); + break; + + case NVME_WRITE_ZEROES: + // LBA value is passed through Command Dword 10,11,12,13,14 and 15, return error if any one of the + // Command Dword is invalid + if( (Packet->NvmeCmd->Flags & (CDW14_VALID|CDW15_VALID)) != (CDW14_VALID|CDW15_VALID)) { + break; + } + + case NVME_WRITE_UNCORRECTABLE: + // LBA value is passed through Command Dword 10,11 and 12, return error if any one of the + // Command Dword is invalid + if( !(Packet->NvmeCmd->Flags & CDW12_VALID)) { + break; + } + case NVME_DATASET_MANAGEMENT: + // LBA value is passed through Command Dword 10,11 return error if any one of the + // Command Dword is invalid + if( (Packet->NvmeCmd->Flags & (CDW10_VALID |CDW11_VALID)) != (CDW10_VALID |CDW11_VALID)) { + break; + } + case NVME_FLUSH: + // Send Nvme Command + Status = ExecuteNvmeCmd (NvmeController, NvmeCmdWrapper, (COMPLETION_QUEUE_ENTRY*)NvmeCompletionData); + break; + default: + Status = EFI_UNSUPPORTED; + break; + } + } +PassthruErrorExit: + + if( NvmeCmdWrapper ) { + pBS->FreePool ( NvmeCmdWrapper ); + } + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: GetNextNamespace +// +// Description: +// API to get next valid NameSpace ID of the Nvme Device +// +// Input: +// IN This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance +// IN NamespaceId A pointer to a valid Namespace ID on this NVM Express controller +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +GetNextNamespace( + IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, + IN OUT UINT32 *NamespaceId +) +{ + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController; + ACTIVE_NAMESPACE_DATA *ActiveNameSpaceData; + LIST_ENTRY *LinkData; + BOOLEAN ReturnNextNameSpaceId = FALSE; + + if(!NamespaceId || !This) { + return EFI_INVALID_PARAMETER; + } + if( 0xFFFFFFFF == *NamespaceId) { + ReturnNextNameSpaceId = TRUE; + } + + NvmeController = NVME_CONTROLLER_PROTOCOL_FROM_THIS(This); + + for (LinkData = NvmeController->ActiveNameSpaceList.ForwardLink; + LinkData != &NvmeController->ActiveNameSpaceList; + LinkData = LinkData->ForwardLink) { + + ActiveNameSpaceData = _CR(LinkData ,ACTIVE_NAMESPACE_DATA, Link); + + if( TRUE == ReturnNextNameSpaceId) { + *NamespaceId = ActiveNameSpaceData->ActiveNameSpaceID; + return EFI_SUCCESS; + } + + if(ActiveNameSpaceData->ActiveNameSpaceID == *NamespaceId) { + ReturnNextNameSpaceId = TRUE; + } + } + + return EFI_NOT_FOUND; +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: SearchDevicePathNode +// +// Description: +// Routine Searches device path by specific Type and SubType +// +// Input: +// IN DevicePath A pointer to the device path protocol +// IN Type Device path Node Type +// IN SubType Device path node subtype +// +// Output: +// EFI_DEVICE_PATH_PROTOCOL* +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_DEVICE_PATH_PROTOCOL* +SearchDevicePathNode ( + IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINT8 Type, + IN UINT8 SubType +) +{ + if (DevicePath == NULL) { + return NULL; + } + + while (!isEndNode (DevicePath)) { + if ((DevicePathType (DevicePath) == Type) && (DevicePathSubType (DevicePath) == SubType)) { + return DevicePath; + } + DevicePath = NextDevicePathNode (DevicePath); + } + + return NULL; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: BuildDevicePath +// +// Description: +// Used to allocate and build a device path node for an NVM Express namespace +// on an NVM Express controller +// +// Input: +// IN This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance +// IN NamespaceId The NVM Express namespace ID for which a device path node is +// to be allocated and built +// IN DevicePath A pointer to a single device path node that describes the +// NVM Express namespace specified by NamespaceId. +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +BuildDevicePath ( + IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, + IN UINT32 NamespaceId, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath +) +{ + EFI_STATUS Status; + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController; + LIST_ENTRY *LinkData; + ACTIVE_NAMESPACE_DATA *ActiveNameSpaceData; + EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol; + NVME_DEVICE_PATH *NvmeDevicePathNode = NULL; + + if( !DevicePath || !This ) { + return EFI_INVALID_PARAMETER; + } + + Status = pBS->AllocatePool( EfiBootServicesData, + sizeof(NVME_DEVICE_PATH), + (void**)DevicePath ); + if(EFI_ERROR(Status)) { + return EFI_OUT_OF_RESOURCES; + } + + NvmeController = NVME_CONTROLLER_PROTOCOL_FROM_THIS(This); + + for (LinkData = NvmeController->ActiveNameSpaceList.ForwardLink; + LinkData != &NvmeController->ActiveNameSpaceList; + LinkData = LinkData->ForwardLink) { + + ActiveNameSpaceData = _CR(LinkData ,ACTIVE_NAMESPACE_DATA, Link); + + if(ActiveNameSpaceData->ActiveNameSpaceID == NamespaceId) { + + Status = pBS->HandleProtocol ( + ActiveNameSpaceData->NvmeDeviceHandle, + &gEfiDevicePathProtocolGuid, + &DevicePathProtocol ); + + NvmeDevicePathNode = (NVME_DEVICE_PATH*)SearchDevicePathNode ( DevicePathProtocol, MESSAGING_DEVICE_PATH, MSG_NVME_DP); + + pBS->CopyMem( (UINT8*)*DevicePath, (UINT8*)NvmeDevicePathNode, sizeof(NVME_DEVICE_PATH) ); + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: GetNamespace +// +// Description: +// Used to translate a device path node to a Namespace ID +// +// +// Input: +// IN This A pointer to the EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL instance +// IN DevicePath A pointer to the device path node that describes an NVM +// Express namespace on the NVM Express controller. +// IN NamespaceId The NVM Express namespace ID contained in the device path node +// +// Output: +// EFI_STATUS +// +// Modified: +// +// Referrals: +// +// Notes: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +GetNamespace ( + IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT32 *NamespaceId +) +{ + UINT16 DevicePathLength = 0; + + if(!DevicePath || !This || !NamespaceId) { + return EFI_INVALID_PARAMETER; + } + + DevicePathLength = (DevicePath)->Length[0] | (DevicePath)->Length[1] << 8; + + if ((DevicePath->Type != MESSAGING_DEVICE_PATH) || + (DevicePath->SubType != MSG_NVME_DP) || + (DevicePathLength != sizeof(NVME_DEVICE_PATH))) { + return EFI_UNSUPPORTED; + } + + *NamespaceId = ((NVME_DEVICE_PATH* )DevicePath)->Nsid; + + return EFI_SUCCESS; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmePassthru.h b/Core/EM/Nvme/NvmePassthru.h new file mode 100644 index 0000000..2f61000 --- /dev/null +++ b/Core/EM/Nvme/NvmePassthru.h @@ -0,0 +1,107 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (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/NvmePassthru.h 1 5/14/15 2:36a Karthikar $ +// +// $Revision: 1 $ +// +// $Date: 5/14/15 2:36a $ +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmePassthru.h +// +// Description: Header file for NvmePassthru.h file +// +//<AMI_FHDR_END> +//********************************************************************** + + +#ifndef __NVM_PASS_THRU_H__ +#define __NVM_PASS_THRU_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <Efi.h> +#include "Protocol/AmiNvmeController.h" +#include "Protocol/NvmExpressPassThru.h" +#include "EdkIICommon.h" + +#define LIST_ENTRY EFI_LIST_ENTRY + + +#define NVME_ADMIN_SUBMISSION_QUEUE 0x00 +#define NVME_IO_SUBMISSION_QUEUE 0x01 + +#define NVME_CONTROLLER_PROTOCOL_FROM_THIS(NvmePassthruProtocol) \ + ((_CR( NvmePassthruProtocol ,NVM_EXPRESS_PASS_THRU_INSTANCE, EfiNvmExpressPassThru))->NvmeControllerProtocol) + +typedef +struct _NVM_EXPRESS_PASS_THRU_INSTANCE { + EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL EfiNvmExpressPassThru; // Instance of EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL + AMI_NVME_CONTROLLER_PROTOCOL *NvmeControllerProtocol; + EFI_HANDLE ControllerHandle; +} NVM_EXPRESS_PASS_THRU_INSTANCE; + +EFI_STATUS +NvmePassThru ( + IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, + IN UINT32 NamespaceId, + IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event +); + +EFI_STATUS +GetNextNamespace( + IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, + IN OUT UINT32 *NamespaceId +); + +EFI_STATUS +BuildDevicePath ( + IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, + IN UINT32 NamespaceId, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath +); + +EFI_STATUS +GetNamespace ( + IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT32 *NamespaceId +); + +#ifdef __cplusplus +} +#endif + +#endif // __NVM_PASS_THRU_H__ + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + diff --git a/Core/EM/Nvme/NvmeSetup.c b/Core/EM/Nvme/NvmeSetup.c new file mode 100644 index 0000000..e1ddd13 --- /dev/null +++ b/Core/EM/Nvme/NvmeSetup.c @@ -0,0 +1,473 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (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/NvmeSetup.c 5 5/19/15 5:08a Ksudarsanan $ +// +// $Revision: 5 $ +// +// $Date: 5/19/15 5:08a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeSetup.c $ +// +// 5 5/19/15 5:08a Ksudarsanan +// [TAG] EIP218818 +// [Category] Improvement +// [Description] Aptio 4.x: When NVMe device is not connect then in BIOS +// Setup should display "No Nvme device found" +// [Files] Nvme.sd, Nvme.uni, NvmeSetup.c +// +// 4 9/04/14 7:37a Anandakrishnanl +// [TAG] EIP180861 +// [Category] Improvement +// [Description] Legacy Boot support in Aptio 4.x Nvme driver +// +// [Files] +// Nvme.cif +// Nvme.mak +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// [NvmeControllerLib] +// [NvmeSmm] +// [NVMEINT13] +// [NvmeProtocol] +// +// 2 7/02/14 8:31a Anandakrishnanl +// [TAG] EIP175772 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] AMI Nvme Driver setup tries to display the devices detected +// by UEFI option rom +// [RootCause] Display to Nvme devices information did not chack for +// ontroller handle to confirm if gAmiNvmeControllerProtocol is present +// [Solution] Added checking in the controller handle to confirm if +// gAmiNvmeControllerProtocol is present or not. +// [Files] NvmeSetup.c +// +// 1 6/20/14 6:27a Anandakrishnanl +// [TAG] EIP172958 +// [Category] New Feature +// [Description] Nvme Driver Intial Checkin +// [Files] Nvme.cif +// Nvme.sdl +// Nvme.mak +// Nvme.sd +// Nvme.uni +// Nvme.chm +// NvmeSetup.c +// NvmeBus.c +// NvmeController.c +// NvmeComponentName.c +// NvmeIncludes.h +// NvmeBus.h +// NvmeController.h +// +//********************************************************************** +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: NvmeSetup.c +// +// Description: Display the Nvme Controller and device information in the Setup +// +//<AMI_FHDR_END> +//********************************************************************** +#include <AmiLib.h> +#include <AmiDxeLib.h> +#include <Setup.h> +#include <SetupStrTokens.h> +#include <Protocol\DevicePath.h> +#include <Token.h> +#include "NvmeIncludes.h" +#include "NvmeBus.h" + +#define MSG_NVME_DP 23 +#define DRIVEMAXCOUNT 4 + +extern EFI_RUNTIME_SERVICES *pRS; + +typedef struct { + STRING_REF ControllerString; + STRING_REF DeviceString; +} NVME_SETUP_STRUC; + +NVME_SETUP_STRUC NVMeSetupStruc[] = { + {STRING_TOKEN(STR_NVME0_CONTROLLER), STRING_TOKEN(STR_NVME0_NAME)}, + {STRING_TOKEN(STR_NVME1_CONTROLLER), STRING_TOKEN(STR_NVME1_NAME)}, + {STRING_TOKEN(STR_NVME2_CONTROLLER), STRING_TOKEN(STR_NVME2_NAME)}, + {STRING_TOKEN(STR_NVME3_CONTROLLER), STRING_TOKEN(STR_NVME3_NAME)}, +}; + +static EFI_GUID gAmiNvmeControllerProtocolGuid = AMI_NVME_CONTROLLER_PROTOCOL_GUID; + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: UnicodeStrToAsciiStr +// +// Description: This function converts the content of the Unicode string Source +// to the ASCII string Destination by copying the lower 8 bits of +// each Unicode character and returns Destination +// +// Input: +// Source A pointer to a Null-terminated Unicode string. +// Destination A pointer to a Null-terminated ASCII string. +// +// Output: +// NONE +// +// Modified: +// +// Referrals: +// +// Notes: None +// +// +//<AMI_PHDR_END> +//********************************************************************** +CHAR8* +UnicodeStrToAsciiStr ( + IN CONST CHAR16 *Source, + OUT CHAR8 *Destination + ) +{ + CHAR8 *ReturnValue; + UINTN TempReturnValue; + UINTN TempSource; + + ASSERT (Destination != NULL); + + // + // ASSERT if Source is long than PcdMaximumUnicodeStringLength. + // Length tests are performed inside StrLen(). + // + TempSource = (Wcslen ((CHAR16 *)Source) + 1) * sizeof (*Source); + ASSERT (TempSource != 0); + + // + // Source and Destination should not overlap + // + ASSERT ((UINTN) ((CHAR16 *) Destination - Source) > Wcslen ((CHAR16 *)Source)); + ASSERT ((UINTN) ((CHAR8 *) Source - Destination) > Wcslen ((CHAR16 *)Source)); + + + ReturnValue = Destination; + while (*Source != '\0') { + // + // If any Unicode characters in Source contain + // non-zero value in the upper 8 bits, then ASSERT(). + // + ASSERT (*Source < 0x100); + *(Destination++) = (CHAR8) *(Source++); + } + + *Destination = '\0'; + + // + // ASSERT Original Destination is less long than PcdMaximumAsciiStringLength. + // Length tests are performed inside AsciiStrLen(). + // + TempReturnValue = (Strlen((CHAR8 *)ReturnValue) + 1) * sizeof (*ReturnValue); + ASSERT (TempReturnValue!= 0); + + return ReturnValue; +} + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: InitNvmeStrings +// +// Description: This function initializes the SB related setup option values +// +// Input: +// IN EFI_HII_HANDLE HiiHandle - Handle to HII database +// IN UINT16 Class - Indicates the setup class +// +// Output: +// NONE +// +// Modified: +// +// Referrals: +// +// Notes: None +// +// +//<AMI_PHDR_END> +//********************************************************************** +VOID +InitNvmeStrings( + IN EFI_HII_HANDLE HiiHandle, + IN UINT16 Class +) +{ + EFI_STATUS Status; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN HandleCountPciIo; + EFI_HANDLE *HandleBufferPciIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_PCI_IO_PROTOCOL *PciIO; + AMI_NVME_CONTROLLER_PROTOCOL *NvmeController = NULL; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; + UINTN OpenInfoCount; + UINTN IndexPciIo; + UINTN IndexOpenInfo; + EFI_HANDLE DeviceHandle; + EFI_HANDLE ControllerHandle; + EFI_HANDLE DriverBindingHandle; + EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2Protocol; + CHAR16 *DriveNameUni; + CHAR8 *NewString; + UINTN SegmentNumber; + UINTN BusNumber; + UINTN DeviceNumber; + UINTN FunctionNumber; + UINT8 DrivePresence[DRIVEMAXCOUNT] = {0}; + UINT8 DriveIndex = 0; + SETUP_DATA *SetupData; + EFI_GUID SetupGuid = SETUP_GUID; + UINTN SetupSize = sizeof(SETUP_DATA); + UINT32 Attribute = 0; + + + if (Class == ADVANCED_FORM_SET_CLASS) { + // Collect all DevicePath protocol and check for NVMe Controller + Status = pBS->LocateHandleBuffer( + ByProtocol, + &gEfiDevicePathProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + + if (EFI_ERROR(Status)) return; + + for (Index = 0; Index < HandleCount; Index++) { + + Status = pBS->HandleProtocol( + HandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID *)&DevicePath + ); + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) { + continue; + } + + DevicePathNode = DevicePath; + while (!isEndNode (DevicePathNode)) { + if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) && + (DevicePathNode->SubType == MSG_NVME_DP)) { + break; + } + + DevicePathNode = NEXT_NODE(DevicePathNode); + } + + if (DevicePathNode == NULL || isEndNode (DevicePathNode)) { + continue; + } + + // NVMe Device Handle is found. + DeviceHandle = HandleBuffer[Index]; + + // NVMe device is found. Now get the CONTROLLER. Check all the PCIio handles. + Status = pBS->LocateHandleBuffer( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCountPciIo, + &HandleBufferPciIo + ); + + for (IndexPciIo = 0; IndexPciIo < HandleCountPciIo; IndexPciIo++) { + Status = pBS->HandleProtocol( + HandleBufferPciIo[IndexPciIo], + &gEfiPciIoProtocolGuid, + (VOID *)&PciIO + ); + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) { + continue; + } + + Status = pBS->HandleProtocol( + HandleBufferPciIo[IndexPciIo], + &gAmiNvmeControllerProtocolGuid, + (VOID *)&NvmeController + ); + + // If Ami Nvme Controller Protocol not found on the Controller handle ( PciIo handle) + // do not process the Pci Io Handle + if(EFI_ERROR(Status)) { + continue; + } + + OpenInfoCount = 0; + Status = pBS->OpenProtocolInformation( + HandleBufferPciIo[IndexPciIo], + &gEfiPciIoProtocolGuid, + &OpenInfo, + &OpenInfoCount + ); + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) { + continue; + } + + for (IndexOpenInfo = 0; IndexOpenInfo < OpenInfoCount; IndexOpenInfo++) { + + //Check if the handle is opened BY_CHILD and also comnpare the device handle. + if ((OpenInfo[IndexOpenInfo].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) && + (OpenInfo[IndexOpenInfo].ControllerHandle == DeviceHandle)){ + + DriverBindingHandle = OpenInfo[IndexOpenInfo].AgentHandle; + // Get the handle for the Controller + ControllerHandle = HandleBufferPciIo[IndexPciIo]; + + // Now PCI controller and DriverBinding handle is found. Get the Component2Protocol now. + Status = pBS->HandleProtocol( + DriverBindingHandle, + &gEfiComponentName2ProtocolGuid, + (VOID *)&ComponentName2Protocol + ); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) { + continue; + } + + Status = ComponentName2Protocol->GetControllerName ( + ComponentName2Protocol, + ControllerHandle, + DeviceHandle, + LANGUAGE_CODE_ENGLISH, + &DriveNameUni + ); + + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) { + continue; + } + + Status = pBS->AllocatePool( + EfiBootServicesData, + 256, + (VOID *) &NewString); + ASSERT_EFI_ERROR (Status); + + UnicodeStrToAsciiStr (DriveNameUni, NewString); + + InitString( + HiiHandle, + NVMeSetupStruc[DriveIndex].DeviceString, + L"%S", + NewString + ); + + Status = PciIO->GetLocation ( + PciIO, + &SegmentNumber, + &BusNumber, + &DeviceNumber, + &FunctionNumber + ); + + Sprintf(NewString, "Bus:%X Dev:%x Func:%x", BusNumber, DeviceNumber, FunctionNumber); + + InitString( + HiiHandle, + NVMeSetupStruc[DriveIndex].ControllerString, + L"%S", + NewString + ); + + //Enable the string to be displayed in setup + DrivePresence[DriveIndex] = 1; + DriveIndex++; + + pBS->FreePool(NewString); + } + } + pBS->FreePool(OpenInfo); + } + pBS->FreePool(HandleBufferPciIo); + } + + pBS->FreePool(HandleBuffer); + + // Update setupdata to show whether strings need to be displayed or not + Status = pBS->AllocatePool(EfiBootServicesData, sizeof (SETUP_DATA),(VOID *) &SetupData); + ASSERT_EFI_ERROR (Status); + + SetupSize = sizeof (SETUP_DATA); + + Status = pRS->GetVariable ( + L"Setup", + &SetupGuid, + &Attribute, + &SetupSize, + SetupData + ); + + if(!EFI_ERROR(Status)){ + SetupData->DeviceCount = DriveIndex; + for (DriveIndex = 0; DriveIndex < DRIVEMAXCOUNT; DriveIndex++){ + SetupData->ShowNVMeDrive[DriveIndex] = DrivePresence[DriveIndex]; + } + + Status = pRS->SetVariable ( + L"Setup", + &SetupGuid, + Attribute, + sizeof (SETUP_DATA), + SetupData + ); + + ASSERT_EFI_ERROR (Status); + + } + pBS->FreePool(SetupData); + } + + return; +} + + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeSmm/NvmeDef.h b/Core/EM/Nvme/NvmeSmm/NvmeDef.h new file mode 100644 index 0000000..3bcc083 --- /dev/null +++ b/Core/EM/Nvme/NvmeSmm/NvmeDef.h @@ -0,0 +1,253 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/NVMe/NvmeSmm/NvmeDef.h 1 9/04/14 7:54a Anandakrishnanl $ +// +// $Revision: 1 $ +// +// $Date: 9/04/14 7:54a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeSmm/NvmeDef.h $ +// +// 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: NvmeDef.h +// +// Description: Nvme Smm and Non Smm interface Definitions +// +//<AMI_FHDR_END> +//********************************************************************** + +#ifndef _AMI_NVME_DEF_H_ +#define _AMI_NVME_DEF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NVME_DATA_EBDA_OFFSET 0x104 + +#define NVME_API_MASS_DEVICE_REQUEST 0x27 + +//---------------------------------------------------------------------------- +// NVME Mass Storage Related Data Structures and Equates +//---------------------------------------------------------------------------- +#define NVME_EMU_NONE 0 +#define NVME_EMU_FLOPPY_ONLY 1 +#define NVME_EMU_HDD_ONLY 2 +#define NVME_EMU_FORCED_FDD 3 + +// Error returned from API handler +#define NVME_SUCCESS 0x000 +#define NVME_PARAMETER_ERROR 0x010 +#define NVME_NOT_SUPPORTED 0x020 +#define NVME_INVALID_FUNCTION 0x0F0 +#define NVME_ERROR 0x0FF + +#pragma pack(1) + +/** + This is a URP (NVME Request Packet) structure for the BIOS + API call Controller Info + + @param TransferBufferAddress + @param NVMEBaseAddress + @param PciBus + @param PciDevice + @param PciFunc + @param Port + @param DeviceDetected + @param DeviceAddress + @param NumHeads + @param LBANumHeads + @param NumCylinders + @param LBANumCyls + @param NumSectors + @param LBANumSectors + @param MaxLBA + @param BlockSize + @param StorageType + @param PNM[27] + @param NVMEDevice + @param NVMEManufactureId[NVME_MANUFACTUREID_LENGTH] + +**/ + +typedef struct { + UINT32 TransferBufferAddress; + UINT64 NVMEBaseAddress; + UINT8 PciBus; + UINT8 PciDevice; + UINT8 PciFunc; + UINT8 Port; + BOOLEAN DeviceDetected; + UINT8 DeviceAddress; + UINT8 NumHeads; + UINT8 LBANumHeads; + UINT16 NumCylinders; + UINT16 LBANumCyls; + UINT8 NumSectors; + UINT8 LBANumSectors; + UINT64 MaxLBA; + UINT16 BlockSize; + UINT8 StorageType; + UINT8 PNM[27]; + BOOLEAN NVMEDevice; + UINT8 NVMEManufactureId[NVME_MANUFACTUREID_LENGTH]; +} CONTROLLER_INFO; + +/** + This is a URP (NVME Request Packet) structure for the BIOS + API call Reset NVME + + @param DeviceAddress +**/ + +typedef struct { + UINT8 DeviceAddress; +} RESET_NVME; + + +/** + This is a URP (NVME Request Packet) structure for the BIOS + API call Read + + @param DeviceAddress + @param Port + @param LBA + @param NumBlks + @param BufferAddress + +**/ + +typedef struct { + UINT8 DeviceAddress; + UINT8 Port; + UINT64 LBA; // Starting LBA address + UINT16 NumBlks; // Number of blocks to read + UINT32 BufferAddress; // Far buffer pointer +} READ_DATA; + + +/** + This is a URP (NVME Request Packet) structure for the BIOS + API call Device Geometry + + @param DeviceAddress + @param NumHeads + @param NumCylinders + @param NumSectors + @param LBANumHeads + @param LBANumCyls + @param LBANumSectors + @param BlockSize + @param MediaType + @param MaxLBA + @param Int13FunctionNo + @param BpbMediaDesc + +**/ +typedef struct { + UINT8 DeviceAddress; + UINT8 NumHeads; + UINT16 NumCylinders; + UINT8 NumSectors; + UINT8 LBANumHeads; + UINT16 LBANumCyls; + UINT8 LBANumSectors; + UINT16 BlockSize; + UINT8 MediaType; + UINT64 MaxLBA; + UINT8 Int13FunctionNo; + UINT8 BpbMediaDesc; +} DEVICE_GEO; + + +/** + This is a union data type of all the API related data + + @param Reset + @param ControllerInfo + @param Read + @param DeviceGeo +**/ + +typedef union { + RESET_NVME Reset; + CONTROLLER_INFO ControllerInfo; + READ_DATA Read; + DEVICE_GEO DeviceGeo; +} NVME_API_DATA; + + +/** + This structure is the URP structure + + @param bFuncNumber + @param bSubFunc + @param bRetValue + @param ApiData + + @note Fields:Name Type Description + -------------------------------------------------- + bFuncNumber UINT8 Function number of the URP + bSubFunc UINT8 Sub-func number of the URP + bRetValue UINT8 Return value + ApiData API_DATA Refer structure definition +**/ + +typedef struct { + UINT8 bFuncNumber; + UINT8 bSubFunc; + UINT8 bRetValue; + NVME_API_DATA ApiData; +} NVME_STRUC; + +#pragma pack() + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif + +#endif +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** 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 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeSmm/NvmeSmm.cif b/Core/EM/Nvme/NvmeSmm/NvmeSmm.cif new file mode 100644 index 0000000..56d3f22 --- /dev/null +++ b/Core/EM/Nvme/NvmeSmm/NvmeSmm.cif @@ -0,0 +1,13 @@ +<component> + name = "NvmeSmm" + category = ModulePart + LocalRoot = "Core\EM\Nvme\NvmeSmm\" + RefName = "NvmeSmm" +[files] +"NvmeSmm.mak" +"NvmeSmm.dxs" +"NvmeSmm.sdl" +"NvmeSmm.c" +"NvmeSmm.h" +"NvmeDef.h" +<endComponent> diff --git a/Core/EM/Nvme/NvmeSmm/NvmeSmm.dxs b/Core/EM/Nvme/NvmeSmm/NvmeSmm.dxs new file mode 100644 index 0000000..e2e23f9 --- /dev/null +++ b/Core/EM/Nvme/NvmeSmm/NvmeSmm.dxs @@ -0,0 +1,89 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, 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.dxs 2 9/23/14 2:33a Anandakrishnanl $ +// +// $Revision: 2 $ +// +// $Date: 9/23/14 2:33a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeSmm/NvmeSmm.dxs $ +// +// 2 9/23/14 2:33a 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.dxs +// +// Description: This file is the dependency file for the NvmeSmm driver +// +//<AMI_FHDR_END> +//********************************************************************** + +#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014) +#include <Protocol\SmmBase2.h> +#include <Protocol\SmmSwDispatch2.h> +#else +#include <Protocol\SmmBase.h> +#include <Protocol\SmmSwDispatch.h> +#endif + +DEPENDENCY_START +#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014) + EFI_SMM_BASE2_PROTOCOL_GUID AND + EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID +#else + EFI_SMM_BASE_PROTOCOL_GUID AND + EFI_SMM_SW_DISPATCH_PROTOCOL_GUID +#endif +DEPENDENCY_END + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeSmm/NvmeSmm.h b/Core/EM/Nvme/NvmeSmm/NvmeSmm.h new file mode 100644 index 0000000..20d13f4 --- /dev/null +++ b/Core/EM/Nvme/NvmeSmm/NvmeSmm.h @@ -0,0 +1,222 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, 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.h 3 12/10/14 5:15a Lavanyap $ +// +// $Revision: 3 $ +// +// $Date: 12/10/14 5:15a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/NVMe/NvmeSmm/NvmeSmm.h $ +// +// 3 12/10/14 5:15a 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:34a 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.h +// +// Description: Header file for the NvmeSmm +// +//<AMI_FHDR_END> +//********************************************************************** + +#ifndef _AMI_NVME_SMM_DRIVER_H_ +#define _AMI_NVME_SMM_DRIVER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <EFI.h> +#include <AmiLib.h> +#include <AmiDxeLib.h> +#if defined(PI_SPECIFICATION_VERSION) && (PI_SPECIFICATION_VERSION >= 0x00010014) +#include <Protocol\SmmBase2.h> +#include <Protocol\SmmSwDispatch2.h> +#else +#include <Protocol\SmmBase.h> +#include <Protocol\SmmSwDispatch.h> +#endif +#include "NvmeIncludes.h" +#include "NvmeBus.h" +#include "NvmeDef.h" +#include <AmiBufferValidationLib.h> + +typedef VOID (*API_FUNC)(NVME_STRUC*); + +//----------------------------------------------- +// ERROR CODE REPORTED TO CALLER +//----------------------------------------------- +#define NVME_WRITE_PROTECT_ERR 0x003 // Write protect error +#define NVME_TIME_OUT_ERR 0x080 // Command timed out error +#define NVME_DRIVE_NOT_READY_ERR 0x0AA // Drive not ready error +#define NVME_DATA_CORRECTED_ERR 0x011 // Data corrected error +#define NVME_PARAMETER_FAILED 0x007 // Bad parameter error +#define NVME_MARK_NOT_FOUND_ERR 0x002 // Address mark not found error +#define NVME_NO_MEDIA_ERR 0x031 // No media in drive +#define NVME_READ_ERR 0x004 // Read error +#define NVME_WRITE_ERR 0x005 // Write error +#define NVME_UNCORRECTABLE_ERR 0x010 // Uncorrectable data error +#define NVME_BAD_SECTOR_ERR 0x00A // Bad sector error +#define NVME_GENERAL_FAILURE 0x020 // Controller general failure + + +//-----------------------------------------------------------------------; +// NVME_GLOBAL_DATA +//-----------------------------------------------------------------------; +typedef struct{ + UINT32 TransferBufferAddress; + UINT8 NvmeMassEmulationOptionTable[MAX_NVME_DEVICES]; + ACTIVE_NAMESPACE_DATA NvmeDev[MAX_NVME_DEVICES]; +} NVME_GLOBAL_DATA; + +// +//NVME Setup fields +// + +typedef struct { + UINT8 NvmeMode; + UINT8 NvmeEmu1; + UINT8 NvmeEmu2; + UINT8 NvmeEmu3; + UINT8 NvmeEmu4; + UINT8 NvmeEmu5; + UINT8 NvmeEmu6; + UINT8 NvmeEmu7; + UINT8 NvmeEmu8; + UINT8 NvmeMassDevNum; +} NVME_DEV_CONFIGURATION; + + +EFI_STATUS +NotInSmmFunction ( + EFI_HANDLE ImageHandle, + EFI_SYSTEM_TABLE *SystemTable +); + +EFI_STATUS +NvmeInSmmFunction ( + EFI_HANDLE ImageHandle, + EFI_SYSTEM_TABLE *SystemTable +); + +#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 + +VOID +ZeroMemorySmm ( + VOID *Buffer, + UINTN Size + ); + +VOID +NvmeMassAPIGetDeviceInformation ( + NVME_STRUC *NvmeURP +); + +VOID +NvmeMassAPIGetDeviceGeometry ( + NVME_STRUC *NvmeURP +); + +VOID +NvmeMassAPIResetDevice ( + NVME_STRUC *NvmeURP +); + +VOID +NvmeMassAPIReadDevice ( + NVME_STRUC *NvmeURP +); + +VOID +NvmeMassAPIWriteDevice ( + NVME_STRUC *NvmeURP +); + +VOID +NvmeMassAPINotSupported ( + NVME_STRUC *NvmeURP +); + +VOID +NvmeMassAPIPass( + NVME_STRUC *NvmeURP +); + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif + +#endif +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/Nvme/NvmeSmm/NvmeSmm.mak b/Core/EM/Nvme/NvmeSmm/NvmeSmm.mak new file mode 100644 index 0000000..3c3636b --- /dev/null +++ b/Core/EM/Nvme/NvmeSmm/NvmeSmm.mak @@ -0,0 +1,95 @@ +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** +#********************************************************************** +# $Header: /Alaska/SOURCE/Modules/NVMe/NvmeSmm/NvmeSmm.mak 3 7/15/15 5:04a Deepthins $ +# +# $Revision: 3 $ +# +# $Date: 7/15/15 5:04a $ +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/NVMe/NvmeSmm/NvmeSmm.mak $ +# +# 3 7/15/15 5:04a Deepthins +# [TAG] EIP228506 +# [Description] Legacy Os installation failing for NVME device in AMD +# platform +# [Files] NvmeSmm.mak +# +# 2 12/10/14 5:16a Lavanyap +# [TAG] EIP185327 +# [Category] Improvement +# [Description] Security Enhancement for SMIHandler in Aptio4.x NVMe +# Driver +# [Files] NvmeSmm.mak, NvmeSmm.c, NvmeSmm.h +# +# 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.mak +# +# Description: Make file for NvmeSmm +# +#<AMI_FHDR_END> +#********************************************************************** +all : NvmeSmm + +NvmeSmm : $(BUILD_DIR)\NvmeSmm.mak NvmeSmmBin + +$(BUILD_DIR)\NvmeSmm.mak : $(NVME_SMM_DIR)\NvmeSmm.cif $(NVME_SMM_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(NVME_SMM_DIR)\NvmeSmm.cif $(CIF2MAK_DEFAULTS) + +NVME_SMM_LIB = $(AMIDXELIB) \ + $(NVMECONTROLLERLIB) \ + $(BUILD_DIR)\AmiBufferValidationLib.lib + +NVME_SMM_INCLUDES=\ + /I$(NVME_DIR)\ + +NvmeSmmBin : $(NVME_SMM_LIB) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\NvmeSmm.mak all\ + GUID=E5E2C9D9-5BF5-497E-8860-94F81A09ADE0\ + ENTRY_POINT=NvmeSmmDriverEntryPoint\ + "MY_INCLUDES=$(NVME_SMM_INCLUDES)"\ + TYPE=SMM_DRIVER\ + COMPRESS=1 + +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** diff --git a/Core/EM/Nvme/NvmeSmm/NvmeSmm.sdl b/Core/EM/Nvme/NvmeSmm/NvmeSmm.sdl new file mode 100644 index 0000000..e9ab0e7 --- /dev/null +++ b/Core/EM/Nvme/NvmeSmm/NvmeSmm.sdl @@ -0,0 +1,35 @@ +TOKEN + Name = "NvmeSmm_SUPPORT" + Value = "1" + Help = "Main switch to enable NvmeSmm support in Project" + TokenType = Boolean + TargetMAK = Yes + TargetH = Yes + Master = Yes + Token = "CSM_SUPPORT" "=" "1" + Token = "NVMEINT13_SUPPORT" "=" "1" +End + +PATH + Name = "NVME_SMM_DIR" +End + +TOKEN + Name = "NVME_INIT_SMM_SWSMI" + Value = "0x45" + Help = "Data to be written to SW SMI port to Init NVME Smm Data." + TokenType = Integer + TargetH = Yes +End + +MODULE + Help = "Includes NvmeSmm.mak to Project" + File = "NvmeSmm.mak" +End + +ELINK + Name = "$(BUILD_DIR)\NvmeSmm.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + |