summaryrefslogtreecommitdiff
path: root/Core/EM/Nvme
diff options
context:
space:
mode:
authorraywu <raywu0301@gmail.com>2018-06-15 00:00:50 +0800
committerraywu <raywu0301@gmail.com>2018-06-15 00:00:50 +0800
commitb7c51c9cf4864df6aabb99a1ae843becd577237c (patch)
treeeebe9b0d0ca03062955223097e57da84dd618b9a /Core/EM/Nvme
downloadzprj-b7c51c9cf4864df6aabb99a1ae843becd577237c.tar.xz
init. 1AQQW051HEADmaster
Diffstat (limited to 'Core/EM/Nvme')
-rw-r--r--Core/EM/Nvme/Nvme.chmbin0 -> 100515 bytes
-rw-r--r--Core/EM/Nvme/Nvme.cif24
-rw-r--r--Core/EM/Nvme/Nvme.mak170
-rw-r--r--Core/EM/Nvme/Nvme.sd170
-rw-r--r--Core/EM/Nvme/Nvme.sdl83
-rw-r--r--Core/EM/Nvme/Nvme.unibin0 -> 7390 bytes
-rw-r--r--Core/EM/Nvme/NvmeBus.c2793
-rw-r--r--Core/EM/Nvme/NvmeBus.h539
-rw-r--r--Core/EM/Nvme/NvmeComponentName.c270
-rw-r--r--Core/EM/Nvme/NvmeController.c1446
-rw-r--r--Core/EM/Nvme/NvmeController.cif12
-rw-r--r--Core/EM/Nvme/NvmeController.h235
-rw-r--r--Core/EM/Nvme/NvmeController.mak86
-rw-r--r--Core/EM/Nvme/NvmeController.sdl31
-rw-r--r--Core/EM/Nvme/NvmeIncludes.h120
-rw-r--r--Core/EM/Nvme/NvmeInt13/NvmeInt13.c474
-rw-r--r--Core/EM/Nvme/NvmeInt13/NvmeInt13.cif16
-rw-r--r--Core/EM/Nvme/NvmeInt13/NvmeInt13.dxs71
-rw-r--r--Core/EM/Nvme/NvmeInt13/NvmeInt13.h161
-rw-r--r--Core/EM/Nvme/NvmeInt13/NvmeInt13.inf5
-rw-r--r--Core/EM/Nvme/NvmeInt13/NvmeInt13.mak84
-rw-r--r--Core/EM/Nvme/NvmeInt13/NvmeInt13.sdl48
-rw-r--r--Core/EM/Nvme/NvmePassthru.c619
-rw-r--r--Core/EM/Nvme/NvmePassthru.h107
-rw-r--r--Core/EM/Nvme/NvmeSetup.c473
-rw-r--r--Core/EM/Nvme/NvmeSmm/NvmeDef.h253
-rw-r--r--Core/EM/Nvme/NvmeSmm/NvmeSmm.c1127
-rw-r--r--Core/EM/Nvme/NvmeSmm/NvmeSmm.cif13
-rw-r--r--Core/EM/Nvme/NvmeSmm/NvmeSmm.dxs89
-rw-r--r--Core/EM/Nvme/NvmeSmm/NvmeSmm.h222
-rw-r--r--Core/EM/Nvme/NvmeSmm/NvmeSmm.mak95
-rw-r--r--Core/EM/Nvme/NvmeSmm/NvmeSmm.sdl35
32 files changed, 9871 insertions, 0 deletions
diff --git a/Core/EM/Nvme/Nvme.chm b/Core/EM/Nvme/Nvme.chm
new file mode 100644
index 0000000..1d8fee0
--- /dev/null
+++ b/Core/EM/Nvme/Nvme.chm
Binary files differ
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
new file mode 100644
index 0000000..4f931cb
--- /dev/null
+++ b/Core/EM/Nvme/Nvme.uni
Binary files differ
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
+