Add the AMD Family10 Agesa code
[coreboot.git] / src / vendorcode / amd / agesa / f10 / Proc / CPU / Feature / cpuSrat.c
diff --git a/src/vendorcode/amd/agesa/f10/Proc/CPU/Feature/cpuSrat.c b/src/vendorcode/amd/agesa/f10/Proc/CPU/Feature/cpuSrat.c
new file mode 100755 (executable)
index 0000000..bf13604
--- /dev/null
@@ -0,0 +1,614 @@
+/**
+ * @file
+ *
+ * AMD SRAT, ACPI table related API functions.
+ *
+ * Contains code that Create the APCI SRAT Table after early reset.
+ *
+ * @xrefitem bom "File Content Label" "Release Content"
+ * @e project:      AGESA
+ * @e sub-project:  CPU
+ * @e \$Revision: 44323 $   @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $
+ *
+ */
+/*
+ ******************************************************************************
+ *
+ * Copyright (c) 2011, Advanced Micro Devices, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Advanced Micro Devices, Inc. nor the names of 
+ *       its contributors may be used to endorse or promote products derived 
+ *       from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ ***************************************************************************/
+
+
+/*----------------------------------------------------------------------------
+ * This file provides functions, that will generate SRAT tables
+ *----------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------------------
+ *                            M O D U L E S    U S E D
+ *----------------------------------------------------------------------------------------
+ */
+#include "AGESA.h"
+#include "amdlib.h"
+#include "cpuServices.h"
+#include "OptionSrat.h"
+#include "cpuRegisters.h"
+#include "cpuLateInit.h"
+#include "Ids.h"
+#include "Filecode.h"
+#define FILECODE PROC_CPU_FEATURE_CPUSRAT_FILECODE
+
+/*----------------------------------------------------------------------------------------
+ *                          EXPORTED FUNCTIONS
+ *----------------------------------------------------------------------------------------
+ */
+AGESA_STATUS
+GetAcpiSratStub (
+  IN OUT   AMD_CONFIG_PARAMS     *StdHeader,
+  IN OUT   VOID                  **SratPtr
+  );
+AGESA_STATUS
+GetAcpiSratMain (
+  IN OUT   AMD_CONFIG_PARAMS     *StdHeader,
+  IN OUT   VOID                  **SratPtr
+  );
+/*----------------------------------------------------------------------------------------
+ *                   D E F I N I T I O N S    A N D    M A C R O S
+ *----------------------------------------------------------------------------------------
+ */
+extern OPTION_SRAT_CONFIGURATION OptionSratConfiguration;  // global user config record
+
+#define NodeID 0x60
+#define FOURGB 0x010000
+
+/*----------------------------------------------------------------------------------------
+ *                  T Y P E D E F S     A N D     S T R U C T U R E S
+ *----------------------------------------------------------------------------------------
+ */
+
+/*----------------------------------------------------------------------------
+ *  All of the DATA should be defined in _CODE segment.
+ *  Use ROMDATA to specify that it belongs to _CODE.
+ *----------------------------------------------------------------------------
+ */
+STATIC CPU_SRAT_HEADER  ROMDATA CpuSratHdrStruct =
+{
+  {'S','R','A','T'},
+  0,
+  2,
+  0,
+  {'A','M','D',' ',' ',' '},
+  {'F','1','0',' ',' ',' ',' ',' '},
+  1,
+  {'A','M','D',' '},
+  1,
+  1,
+  {0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+/*----------------------------------------------------------------------------------------
+ *           P R O T O T Y P E S     O F     L O C A L     F U  N C T I O N S
+ *----------------------------------------------------------------------------------------
+ */
+UINT8
+STATIC
+*MakeApicEntry (
+  IN UINT8 ApicId,
+  IN UINT8 Domain,
+  IN UINT8 *BufferLocPtr
+  );
+
+UINT8
+STATIC
+*FillMemoryForCurrentNode (
+  IN      UINT8 *PDomain,
+  IN OUT  UINT8 *PDomainForBase640K,
+  IN      UINT8 Node,
+  IN OUT  UINT8 *BufferLocPtr,
+  IN OUT  AMD_CONFIG_PARAMS *StdHeader
+  );
+
+UINT8
+STATIC
+*MakeMemEntry (
+  IN UINT8  PDomain,
+  IN UINT8  Node,
+  IN UINT32 Base,
+  IN UINT32 Size,
+  IN UINT8  *BufferLocPtr
+  );
+
+/*----------------------------------------------------------------------------------------
+ *                          E X P O R T E D    F U N C T I O N S
+ *----------------------------------------------------------------------------------------
+ */
+/*---------------------------------------------------------------------------------------*/
+/**
+ *
+ * This function will generate a complete Static Resource Affinity Table
+ * i.e. SRAT into a memory buffer. After completion, this table must be set
+ * by the system BIOS into its internal ACPI name space.
+ *
+ *    @param[in, out] StdHeader         Standard Head Pointer
+ *    @param[in, out] SratPtr           Point to Srat Struct including buffer address and length
+ *
+ *    @retval         AGESA_STATUS
+ */
+
+AGESA_STATUS
+CreateAcpiSrat (
+  IN OUT   AMD_CONFIG_PARAMS     *StdHeader,
+  IN OUT   VOID                  **SratPtr
+  )
+{
+  AGESA_TESTPOINT (TpProcCpuEntrySrat, StdHeader);
+  return ((*(OptionSratConfiguration.SratFeature)) (StdHeader, SratPtr));
+}
+
+/*---------------------------------------------------------------------------------------*/
+/**
+ *
+ * This is the default routine for use when the SRAT option is NOT requested.
+ *
+ * The option install process will create and fill the transfer vector with
+ * the address of the proper routine (Main or Stub). The link optimizer will
+ * strip out of the .DLL the routine that is not used.
+ *
+ *    @param[in, out] StdHeader      Standard Head Pointer
+ *    @param[in, out] SratPtr           Point to Srat Struct including buffer address and length
+ *
+ *    @retval         AGESA_STATUS
+ */
+
+AGESA_STATUS
+GetAcpiSratStub (
+  IN OUT   AMD_CONFIG_PARAMS     *StdHeader,
+  IN OUT   VOID                  **SratPtr
+  )
+{
+  return  AGESA_UNSUPPORTED;
+}
+/*---------------------------------------------------------------------------------------*/
+/**
+ *
+ * This function will generate a complete Static Resource Affinity Table
+ * i.e. SRAT into a memory buffer. After completion, this table must be set
+ * by the system BIOS into its internal ACPI name space.
+ *
+ *    @param[in, out] StdHeader         Standard Head Pointer
+ *    @param[in, out] SratPtr           Point to Srat Struct including buffer address and length
+ *
+ *    @retval         AGESA_STATUS
+ */
+AGESA_STATUS
+GetAcpiSratMain (
+  IN OUT   AMD_CONFIG_PARAMS     *StdHeader,
+  IN OUT   VOID                  **SratPtr
+  )
+{
+  UINT8     *BufferPtr;
+  UINT8     NodeNum;
+  UINT8     NodeCount;
+  UINT8     PDomain;
+  UINT8     PDomainForBase640K;
+  UINT32    Socket;
+  UINT32    Module;
+  UINT32    LowCore;
+  UINT32    HighCore;
+  UINT32    CoreNum;
+  UINT32    RegVal;
+  UINT32    tempVar_32;
+  AMD_APIC_PARAMS ApicParams;
+  PCI_ADDR  PciAddress;
+  CPU_SRAT_HEADER  *CpuSratHeaderStructPtr;
+  AGESA_BUFFER_PARAMS AllocParams;
+
+  // Get Node count
+  PciAddress.AddressValue = MAKE_SBDFO (0, 0, LOW_NODE_DEVICEID, FUNC_0, NodeID);
+  LibAmdPciRead (AccessWidth32 , PciAddress, &RegVal, StdHeader);
+  NodeCount = (UINT8) (((RegVal >> 4) & 0x7) + 1);
+
+  // The worst-case buffer size to request is for the SRAT table header, one
+  // entree for special region (base 640k block), two memory
+  // regions per node, and APIC entries for each core in the system.
+  tempVar_32 = (sizeof (CPU_SRAT_HEADER)) + (sizeof (CPU_SRAT_MEMORY_ENTRY))
+               + ((UINT32) NodeCount * (2 * (sizeof (CPU_SRAT_MEMORY_ENTRY))
+               + (MAX_NUMBER_CORES * sizeof (CPU_SRAT_APIC_ENTRY))));
+
+  if (*SratPtr == NULL) {
+    //
+    // Allocate a buffer by callback function
+    //
+    AllocParams.StdHeader = *StdHeader;
+    AllocParams.BufferLength = tempVar_32;
+    AllocParams.BufferHandle = AMD_SRAT_INFO_BUFFER_HANDLE;
+
+    AGESA_TESTPOINT (TpProcCpuBeforeAllocateSratBuffer, StdHeader);
+    if (AgesaAllocateBuffer (0, &AllocParams) != AGESA_SUCCESS) {
+      return AGESA_ERROR;
+    }
+    AGESA_TESTPOINT (TpProcCpuAfterAllocateSratBuffer, StdHeader);
+
+    *SratPtr = AllocParams.BufferPointer;
+  }
+
+  CpuSratHeaderStructPtr = (CPU_SRAT_HEADER *) *SratPtr;
+  BufferPtr = (UINT8 *) *SratPtr;
+
+  // Copy acpiSRATHeader -> data buffer
+  LibAmdMemCopy (*SratPtr, (VOID *) &CpuSratHdrStruct, (UINTN) (sizeof (CPU_SRAT_HEADER)), StdHeader);
+
+  BufferPtr += sizeof (CPU_SRAT_HEADER);
+
+  // Place all memory and IO affinity entries
+  NodeNum = 0;
+  PDomain = 0;
+  PDomainForBase640K = 0xFF;
+  ApicParams.StdHeader = *StdHeader;
+  while (NodeNum < NodeCount) {
+    GetSocketModuleOfNode ((UINT32) NodeNum, &Socket, &Module, StdHeader);
+    GetGivenModuleCoreRange (Socket, Module, &LowCore, &HighCore, StdHeader);
+    BufferPtr = FillMemoryForCurrentNode (&PDomain, &PDomainForBase640K, NodeNum, BufferPtr, StdHeader);
+    for (CoreNum = LowCore; CoreNum <= HighCore; CoreNum++) {
+      ApicParams.Socket = (UINT8) Socket;
+      ApicParams.Core = (UINT8) CoreNum;
+      AmdGetApicId (&ApicParams);
+      if (ApicParams.IsPresent) {
+        BufferPtr = MakeApicEntry (ApicParams.ApicAddress, PDomain, BufferPtr);
+      }
+    }
+
+    NodeNum++;
+    PDomain = NodeNum;
+  }
+
+  // Store size in table (current buffer offset - buffer start offset)
+  CpuSratHeaderStructPtr->TableLength = (UINT32) (BufferPtr - (UINT8 *) CpuSratHeaderStructPtr);
+
+  //Update SSDT header Checksum
+  ChecksumAcpiTable ((ACPI_TABLE_HEADER *) CpuSratHeaderStructPtr, StdHeader);
+
+  return AGESA_SUCCESS;
+}
+
+
+/*----------------------------------------------------------------------------------------
+ *                            L O C A L    F U N C T I O N S
+ *----------------------------------------------------------------------------------------
+ */
+
+/*---------------------------------------------------------------------------------------*/
+/**
+ *
+ * This function will build Memory entry for current node.
+ * Note that we only create a memory affinity entry if we find one
+ * that matches the current node.  This makes an easier to read table
+ * though it is not necessary.
+ *
+ *    @param[in]      PDomain            Proximity Domain
+ *    @param[in, out] PDomainForBase640K The PDomain for Base 640K
+ *    @param[in]      Node               The number of Node
+ *    @param[in, out] BufferLocPtr       Point to the address of buffer
+ *    @param[in, out] StdHeader          Standard Head Pointer
+ *
+ *    @retval         UINT8 *(New buffer location ptr)
+ */
+UINT8
+STATIC
+*FillMemoryForCurrentNode (
+  IN      UINT8 *PDomain,
+  IN OUT  UINT8 *PDomainForBase640K,
+  IN      UINT8 Node,
+  IN OUT  UINT8 *BufferLocPtr,
+  IN OUT  AMD_CONFIG_PARAMS *StdHeader
+  )
+{
+  UINT32    ValueLimit;
+  UINT32    ValueTOM;
+  BOOLEAN   isModified;
+  UINT8     Domain;
+  UINT32    RegVal;
+  UINT32    DramLeng;
+  UINT32    DramBase;
+  UINT32    DramLimit;
+  UINT32    OffsetRegs;
+  PCI_ADDR  PciAddress;
+  UINT64    MsrValue;
+  UINT32    TopOfMemoryAbove4Gb;
+
+  Domain = *PDomain;
+
+  PciAddress.Address.Segment = 0;
+  PciAddress.Address.Bus = 0;
+  PciAddress.Address.Device = LOW_NODE_DEVICEID;
+  PciAddress.Address.Function = FUNC_1;
+
+  for (OffsetRegs = DRAMBase0; OffsetRegs < MMIOBase0; OffsetRegs += 8) {
+    isModified = FALSE;        // FALSE means normal update procedure
+    // Get DRAM Base Address
+    PciAddress.Address.Register = OffsetRegs;
+    LibAmdPciRead (AccessWidth32, PciAddress, &DramBase, StdHeader);
+    if ((DramBase & 3) != 3) {
+      // 0:1 set if memory range enabled
+      // Not set, so we don't have an enabled range
+      continue;   // Proceed to next Base register
+    }
+
+    // Get DRAM Limit
+    PciAddress.Address.Register = OffsetRegs + 4;
+    LibAmdPciRead (AccessWidth32, PciAddress, &DramLimit, StdHeader);
+    if (DramLimit == 0xFFFFFFFF) {
+      // Node not installed(all FF's)?
+      continue;   // Proceed to next Base register
+    }
+
+    if ((DramLimit & 0xFF) != Node) {
+      // Check if Destination Node ID is current node
+      continue;   // Proceed to next Base register
+    }
+
+    //    We only add an entry now if detected range belongs to current node/PDomain
+    PciAddress.Address.Register = OffsetRegs + 0x104;
+    LibAmdPciRead (AccessWidth32, PciAddress, &RegVal, StdHeader);
+
+    DramLimit = (((RegVal & 0xFF) << 16) | (DramLimit >> 16));  // Get DRAM Limit addr [47:24]
+    DramLimit++;                     // Add 1 for potential length
+    DramLimit <<= 8;
+
+    // Get DRAM Base Address
+    PciAddress.Address.Register = OffsetRegs + 0x100;
+    LibAmdPciRead (AccessWidth32, PciAddress, &RegVal, StdHeader);
+    DramBase = ((((RegVal & 0xFF) << 24) | (DramBase >> 8)) & 0xFFFFFF00);   // Get DRAM Base Base value [47:24]
+    DramLeng = DramLimit - DramBase;    // Subtract base from limit to get length
+
+    //    Leave hole for conventional memory (Less than 640K).  It must be on CPU 0.
+    if (DramBase == 0) {
+      if (*PDomainForBase640K == 0xFF) {
+        // It is the first time that the range start at 0.
+        // If Yes, then Place 1MB memory gap and save Domain to PDomainForBase640K
+        BufferLocPtr = MakeMemEntry (
+                         Domain,
+                         Node,
+                         0,              // Base = 0
+                         0xA0000 >> 16,  // Put it into format used in DRAM regs..
+                         BufferLocPtr
+                         );
+        DramBase += 0x10;       // Add 1MB, so range = 1MB to Top of Region
+        DramLeng -= 0x10;       // Also subtract 1MB from the length
+        *PDomainForBase640K = Domain;        // Save Domain number for memory Less than 640K
+      } else {
+        // If No, there are more than one memory range less than 640K, it should that
+        // node interleaving is enabled. All nodes have the same memory ranges
+        // and all cores in these nodes belong to the same domain.
+        *PDomain = *PDomainForBase640K;
+        return (BufferLocPtr);
+      }
+    }
+    LibAmdMsrRead (TOP_MEM, &MsrValue, StdHeader);
+    ValueTOM   = (UINT32) MsrValue >> 16;    // Save it in 39:24 format
+    ValueLimit = DramBase + DramLeng;        // We need to know how large region is
+
+    LibAmdMsrRead (SYS_CFG, &MsrValue, StdHeader);
+    if ((MsrValue & BIT21) != 0) {
+      LibAmdMsrRead (TOP_MEM2, &MsrValue, StdHeader);
+      TopOfMemoryAbove4Gb = (UINT32) (MsrValue >> 16);    // Save it in 47:16 format
+    } else {
+      TopOfMemoryAbove4Gb = 0xFFFFFFFF;
+    }
+
+    //  SPECIAL CASES:
+    //
+    //  Several conditions require that we process the values of the memory range differently.
+    //  Here are descriptions of the corner cases.
+    //
+    //  1. TRUNCATE LOW - Memory range starts below TOM, ends in TOM (memory hole).  For this case,
+    //     the range must be truncated to end at TOM.
+    //  *******************************            *******************************
+    //  *                    *        *      ->    *                             *
+    //  *******************************            *******************************
+    //  2                    TOM      4            2                             TOM
+    //
+    //  2. TRUNCATE HIGH - Memory range starts below 4GB, ends above 4GB.  This is handled by changing the
+    //     start base to 4GB.
+    //          ****************                        **********
+    //          *     *        *      ->                *        *
+    //          ****************                        **********
+    //  TOM     3.8   4        6            TOM   3.8   4        6
+    //
+    //  3. Memory range starts below TOM, ends above 4GB.  For this case, the range must be truncated
+    //     to end at TOM.  Note that this scenario creates two ranges, as the second comparison below
+    //     will find that it ends above 4GB since base and limit have been restored after first truncation,
+    //     and a second range will be written based at 4GB ending at original end address.
+    //  *******************************            ****************          **********
+    //  *              *     *        *      ->    *              *          *        *
+    //  *******************************            ****************          **********
+    //  2              TOM   4        6            2              TOM        4        6
+    //
+    //  4. Memory range starts above TOM, ends below or equal to 4GB.  This invalid range should simply
+    //     be ignored.
+    //          *******
+    //          *     *      ->    < NULL >
+    //          *******
+    //  TOM     3.8   4
+    //
+    //  5. Memory range starts below TOM2, and ends beyond TOM2.  This range must be truncated to TOM2.
+    //  ************************         *******************************
+    //  *              *       *   ->    *                             *
+    //  ************************         *******************************
+    //  768          TOM2   1024         768                        TOM2
+    //
+    //  6. Memory range starts above TOM2.  This invalid range should simply be ignored.
+    //          ********************
+    //          *                  *    ->    < NULL >
+    //          ********************
+    //  TOM2    1024            1280
+
+    if (((DramBase < ValueTOM) && (ValueLimit <= FOURGB) && (ValueLimit > ValueTOM))
+        || ((DramBase < ValueTOM) && (ValueLimit > FOURGB))) {
+      //   TRUNCATE LOW!!! Shrink entry below TOM...
+      //   Base = DramBase, Size = TOM - DramBase
+      BufferLocPtr = MakeMemEntry (Domain, Node, DramBase, (ValueTOM - DramBase), BufferLocPtr);
+      isModified = TRUE;
+    }
+
+    if ((ValueLimit > FOURGB) && (DramBase < FOURGB)) {
+      //   TRUNCATE HIGH!!! Shrink entry above 4GB...
+      //   Size = Base + Size - 4GB, Base = 4GB
+      BufferLocPtr = MakeMemEntry (Domain, Node, FOURGB, (DramLeng + DramBase - FOURGB), BufferLocPtr);
+      isModified = TRUE;
+    }
+
+    if ((DramBase >= ValueTOM) && (ValueLimit <= FOURGB)) {
+      //   IGNORE!!!  Entry located entirely within memory hole
+      isModified = TRUE;
+    }
+
+    if ((DramBase < TopOfMemoryAbove4Gb) && (ValueLimit > TopOfMemoryAbove4Gb)) {
+      //   Truncate to TOM2
+      //   Base = DramBase, Size = TOM2 - DramBase
+      BufferLocPtr = MakeMemEntry (Domain, Node, DramBase, (TopOfMemoryAbove4Gb - DramBase), BufferLocPtr);
+      isModified = TRUE;
+    }
+
+    if (DramBase >= TopOfMemoryAbove4Gb) {
+      //   IGNORE!!!  Entry located entirely above TOM2
+      isModified = TRUE;
+    }
+
+    //    If special range(isModified), we are done.
+    //    If not, finally write the memory entry.
+    if (isModified == FALSE) {
+      // Finally write the memory entry.
+      BufferLocPtr = MakeMemEntry (Domain, Node, DramBase, DramLeng, BufferLocPtr);
+    }
+
+  } // for ( OffsetRegs = DRAMBase0; ... )
+
+  return (BufferLocPtr);
+} // FillMemoryForCurrentNode()
+
+
+/*---------------------------------------------------------------------------------------*/
+/**
+ * This function will add APIC entry.
+ *
+ *    @param[in]      ApicId            APIC ID number
+ *    @param[in]      Domain            Domain number
+ *    @param[in]      BufferLocPtr      Point to the address of buffer
+ *
+ *    @retval         UINT8 *(New buffer location ptr)
+ */
+UINT8
+STATIC
+*MakeApicEntry (
+  IN      UINT8 ApicId,
+  IN      UINT8 Domain,
+  IN      UINT8 *BufferLocPtr
+  )
+{
+  CPU_SRAT_APIC_ENTRY *psSratApicEntry;
+  UINT8 ReservedBytes;
+
+  psSratApicEntry = (CPU_SRAT_APIC_ENTRY *)BufferLocPtr;
+
+  psSratApicEntry->Type = AE_APIC;
+  psSratApicEntry->Length = (UINT8)sizeof (CPU_SRAT_APIC_ENTRY);
+  psSratApicEntry->Domain = Domain;
+  psSratApicEntry->ApicId = ApicId;
+  psSratApicEntry->Flags = ENABLED;
+  psSratApicEntry->LSApicEid = 0;
+  for (ReservedBytes = 0; ReservedBytes < (UINT8)sizeof (psSratApicEntry->Reserved); ReservedBytes++) {
+    psSratApicEntry->Reserved[ReservedBytes] = 0;
+  }
+  return (BufferLocPtr + (UINT8)sizeof (CPU_SRAT_APIC_ENTRY));
+} // MakeApicEntry
+
+
+/*---------------------------------------------------------------------------------------*/
+/**
+ *
+ * This function will add Memory entry.
+ *
+ *  Parameters:
+ *    @param[in]  PDomain               Proximity Domain
+ *    @param[in]  Node                  The number of Node
+ *    @param[in]  Base                  Memory Base
+ *    @param[in]  Size                  Memory Size
+ *    @param[in]  BufferLocPtr          Point to the address of buffer
+ *
+ *    @retval       UINT8 * (new buffer location ptr)
+ */
+UINT8
+STATIC
+*MakeMemEntry (
+  IN  UINT8   PDomain,
+  IN  UINT8   Node,
+  IN  UINT32  Base,
+  IN  UINT32  Size,
+  IN  UINT8   *BufferLocPtr
+  )
+{
+  CPU_SRAT_MEMORY_ENTRY *psSratMemEntry;
+  UINT8 ReservedBytes;
+
+  psSratMemEntry = (CPU_SRAT_MEMORY_ENTRY *)BufferLocPtr;
+
+  psSratMemEntry->Type = AE_MEMORY;                       // [0] = Memory Entry
+  psSratMemEntry->Length = (UINT8)sizeof (CPU_SRAT_MEMORY_ENTRY); // [1] = 40
+  psSratMemEntry->Domain = PDomain;                            // [2] = Proximity Domain
+
+  // [6-7] = Reserved
+  for (ReservedBytes = 0; ReservedBytes < (UINT8)sizeof (psSratMemEntry->Reserved1); ReservedBytes++) {
+    psSratMemEntry->Reserved1[ReservedBytes] = 0;
+  }
+
+  // [8-11] = Keep 31:0 of address only -> Base Addr Low
+  psSratMemEntry->BaseAddrLow  = Base << 16;
+
+  // [12-15] = Keep 39:32 of address only -> Base Addr High
+  psSratMemEntry->BaseAddrHigh = Base >> 16;
+
+  // [16-19] = Keep 31:0 of address only -> Length Low
+  psSratMemEntry->LengthAddrLow  = Size << 16;
+
+  // [20-23] = Keep 39:32 of address only -> Length High
+  psSratMemEntry->LengthAddrHigh = Size >> 16;
+
+  // [24-27] = Reserved
+  for (ReservedBytes = 0; ReservedBytes < (UINT8)sizeof (psSratMemEntry->Reserved2); ReservedBytes++) {
+    psSratMemEntry->Reserved2[ReservedBytes] = 0;
+  }
+
+  // [28-31] = Flags
+  psSratMemEntry->Flags = ENABLED;
+
+  // [32-40] = Reserved
+  for (ReservedBytes = 0; ReservedBytes < (UINT8)sizeof (psSratMemEntry->Reserved3); ReservedBytes++) {
+    psSratMemEntry->Reserved3[ReservedBytes] = 0;
+  }
+  return (BufferLocPtr + (UINT8)sizeof (CPU_SRAT_MEMORY_ENTRY));
+} // MakeMemEntry()
+