zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 1 | /* $NoKeywords:$ */ |
| 2 | /** |
| 3 | * @file |
| 4 | * |
| 5 | * AMD SRAT, ACPI table related API functions. |
| 6 | * |
| 7 | * Contains code that Create the APCI SRAT Table after early reset. |
| 8 | * |
| 9 | * @xrefitem bom "File Content Label" "Release Content" |
| 10 | * @e project: AGESA |
| 11 | * @e sub-project: CPU |
| 12 | * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $ |
| 13 | * |
| 14 | */ |
| 15 | /* |
| 16 | ****************************************************************************** |
| 17 | * |
Siyuan Wang | 641f00c | 2013-06-08 11:50:55 +0800 | [diff] [blame] | 18 | * Copyright (c) 2008 - 2012, Advanced Micro Devices, Inc. |
| 19 | * All rights reserved. |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 20 | * |
Siyuan Wang | 641f00c | 2013-06-08 11:50:55 +0800 | [diff] [blame] | 21 | * Redistribution and use in source and binary forms, with or without |
| 22 | * modification, are permitted provided that the following conditions are met: |
| 23 | * * Redistributions of source code must retain the above copyright |
| 24 | * notice, this list of conditions and the following disclaimer. |
| 25 | * * Redistributions in binary form must reproduce the above copyright |
| 26 | * notice, this list of conditions and the following disclaimer in the |
| 27 | * documentation and/or other materials provided with the distribution. |
| 28 | * * Neither the name of Advanced Micro Devices, Inc. nor the names of |
| 29 | * its contributors may be used to endorse or promote products derived |
| 30 | * from this software without specific prior written permission. |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 31 | * |
Siyuan Wang | 641f00c | 2013-06-08 11:50:55 +0800 | [diff] [blame] | 32 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 33 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 34 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 35 | * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY |
| 36 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 37 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 38 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 39 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 40 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 41 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
zbao | 7d94cf9 | 2012-07-02 14:19:14 +0800 | [diff] [blame] | 42 | ***************************************************************************/ |
| 43 | |
| 44 | |
| 45 | /*---------------------------------------------------------------------------- |
| 46 | * This file provides functions, that will generate SRAT tables |
| 47 | *---------------------------------------------------------------------------- |
| 48 | */ |
| 49 | |
| 50 | /*---------------------------------------------------------------------------------------- |
| 51 | * M O D U L E S U S E D |
| 52 | *---------------------------------------------------------------------------------------- |
| 53 | */ |
| 54 | #include "AGESA.h" |
| 55 | #include "amdlib.h" |
| 56 | #include "cpuServices.h" |
| 57 | #include "OptionSrat.h" |
| 58 | #include "heapManager.h" |
| 59 | #include "cpuRegisters.h" |
| 60 | #include "cpuLateInit.h" |
| 61 | #include "Ids.h" |
| 62 | #include "Filecode.h" |
| 63 | CODE_GROUP (G3_DXE) |
| 64 | RDATA_GROUP (G3_DXE) |
| 65 | |
| 66 | #define FILECODE PROC_CPU_FEATURE_CPUSRAT_FILECODE |
| 67 | /*---------------------------------------------------------------------------------------- |
| 68 | * D E F I N I T I O N S A N D M A C R O S |
| 69 | *---------------------------------------------------------------------------------------- |
| 70 | */ |
| 71 | extern OPTION_SRAT_CONFIGURATION OptionSratConfiguration; // global user config record |
| 72 | |
| 73 | #define NodeID 0x60 |
| 74 | #define FOURGB 0x010000ul |
| 75 | |
| 76 | /*---------------------------------------------------------------------------------------- |
| 77 | * T Y P E D E F S A N D S T R U C T U R E S |
| 78 | *---------------------------------------------------------------------------------------- |
| 79 | */ |
| 80 | AGESA_STATUS |
| 81 | GetAcpiSratStub ( |
| 82 | IN OUT AMD_CONFIG_PARAMS *StdHeader, |
| 83 | IN OUT VOID **SratPtr |
| 84 | ); |
| 85 | |
| 86 | AGESA_STATUS |
| 87 | GetAcpiSratMain ( |
| 88 | IN OUT AMD_CONFIG_PARAMS *StdHeader, |
| 89 | IN OUT VOID **SratPtr |
| 90 | ); |
| 91 | |
| 92 | /*---------------------------------------------------------------------------- |
| 93 | * All of the DATA should be defined in _CODE segment. |
| 94 | * Use ROMDATA to specify that it belongs to _CODE. |
| 95 | *---------------------------------------------------------------------------- |
| 96 | */ |
| 97 | STATIC CPU_SRAT_HEADER ROMDATA CpuSratHdrStruct = |
| 98 | { |
| 99 | {'S','R','A','T'}, |
| 100 | 0, |
| 101 | 2, |
| 102 | 0, |
| 103 | {'A','M','D',' ',' ',' '}, |
| 104 | {'A','G','E','S','A',' ',' ',' '}, |
| 105 | 1, |
| 106 | {'A','M','D',' '}, |
| 107 | 1, |
| 108 | 1, |
| 109 | {0, 0, 0, 0, 0, 0, 0, 0} |
| 110 | }; |
| 111 | |
| 112 | /*---------------------------------------------------------------------------------------- |
| 113 | * 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 |
| 114 | *---------------------------------------------------------------------------------------- |
| 115 | */ |
| 116 | UINT8 |
| 117 | STATIC |
| 118 | *MakeApicEntry ( |
| 119 | IN UINT8 ApicId, |
| 120 | IN UINT8 Domain, |
| 121 | IN UINT8 *BufferLocPtr |
| 122 | ); |
| 123 | |
| 124 | UINT8 |
| 125 | STATIC |
| 126 | *FillMemoryForCurrentNode ( |
| 127 | IN UINT8 *PDomain, |
| 128 | IN OUT UINT8 *PDomainForBase640K, |
| 129 | IN UINT8 Node, |
| 130 | IN OUT UINT8 *BufferLocPtr, |
| 131 | IN OUT AMD_CONFIG_PARAMS *StdHeader |
| 132 | ); |
| 133 | |
| 134 | UINT8 |
| 135 | STATIC |
| 136 | *MakeMemEntry ( |
| 137 | IN UINT8 PDomain, |
| 138 | IN UINT8 Node, |
| 139 | IN UINT32 Base, |
| 140 | IN UINT32 Size, |
| 141 | IN UINT8 *BufferLocPtr |
| 142 | ); |
| 143 | |
| 144 | /*---------------------------------------------------------------------------------------- |
| 145 | * E X P O R T E D F U N C T I O N S |
| 146 | *---------------------------------------------------------------------------------------- |
| 147 | */ |
| 148 | /*---------------------------------------------------------------------------------------*/ |
| 149 | /** |
| 150 | * |
| 151 | * This function will generate a complete Static Resource Affinity Table |
| 152 | * i.e. SRAT into a memory buffer. After completion, this table must be set |
| 153 | * by the system BIOS into its internal ACPI name space. |
| 154 | * |
| 155 | * @param[in, out] StdHeader Standard Head Pointer |
| 156 | * @param[in, out] SratPtr Point to Srat Struct including buffer address and length |
| 157 | * |
| 158 | * @retval AGESA_STATUS |
| 159 | */ |
| 160 | |
| 161 | AGESA_STATUS |
| 162 | CreateAcpiSrat ( |
| 163 | IN OUT AMD_CONFIG_PARAMS *StdHeader, |
| 164 | IN OUT VOID **SratPtr |
| 165 | ) |
| 166 | { |
| 167 | AGESA_TESTPOINT (TpProcCpuEntrySrat, StdHeader); |
| 168 | return ((*(OptionSratConfiguration.SratFeature)) (StdHeader, SratPtr)); |
| 169 | } |
| 170 | |
| 171 | /*---------------------------------------------------------------------------------------*/ |
| 172 | /** |
| 173 | * |
| 174 | * This is the default routine for use when the SRAT option is NOT requested. |
| 175 | * |
| 176 | * The option install process will create and fill the transfer vector with |
| 177 | * the address of the proper routine (Main or Stub). The link optimizer will |
| 178 | * strip out of the .DLL the routine that is not used. |
| 179 | * |
| 180 | * @param[in, out] StdHeader Standard Head Pointer |
| 181 | * @param[in, out] SratPtr Point to Srat Struct including buffer address and length |
| 182 | * |
| 183 | * @retval AGESA_STATUS |
| 184 | */ |
| 185 | |
| 186 | AGESA_STATUS |
| 187 | GetAcpiSratStub ( |
| 188 | IN OUT AMD_CONFIG_PARAMS *StdHeader, |
| 189 | IN OUT VOID **SratPtr |
| 190 | ) |
| 191 | { |
| 192 | return AGESA_UNSUPPORTED; |
| 193 | } |
| 194 | /*---------------------------------------------------------------------------------------*/ |
| 195 | /** |
| 196 | * |
| 197 | * This function will generate a complete Static Resource Affinity Table |
| 198 | * i.e. SRAT into a memory buffer. After completion, this table must be set |
| 199 | * by the system BIOS into its internal ACPI name space. |
| 200 | * |
| 201 | * @param[in, out] StdHeader Standard Head Pointer |
| 202 | * @param[in, out] SratPtr Point to Srat Struct including buffer address and length |
| 203 | * |
| 204 | * @retval AGESA_STATUS |
| 205 | */ |
| 206 | AGESA_STATUS |
| 207 | GetAcpiSratMain ( |
| 208 | IN OUT AMD_CONFIG_PARAMS *StdHeader, |
| 209 | IN OUT VOID **SratPtr |
| 210 | ) |
| 211 | { |
| 212 | UINT8 *BufferPtr; |
| 213 | UINT8 NodeNum; |
| 214 | UINT8 NodeCount; |
| 215 | UINT8 PDomain; |
| 216 | UINT8 PDomainForBase640K; |
| 217 | UINT32 Socket; |
| 218 | UINT32 Module; |
| 219 | UINT32 LowCore; |
| 220 | UINT32 HighCore; |
| 221 | UINT32 CoreNum; |
| 222 | UINT32 RegVal; |
| 223 | UINT32 tempVar_32; |
| 224 | AMD_APIC_PARAMS ApicParams; |
| 225 | PCI_ADDR PciAddress; |
| 226 | CPU_SRAT_HEADER *CpuSratHeaderStructPtr; |
| 227 | ALLOCATE_HEAP_PARAMS AllocParams; |
| 228 | |
| 229 | // Get Node count |
| 230 | PciAddress.AddressValue = MAKE_SBDFO (0, 0, LOW_NODE_DEVICEID, FUNC_0, NodeID); |
| 231 | LibAmdPciRead (AccessWidth32 , PciAddress, &RegVal, StdHeader); |
| 232 | NodeCount = (UINT8) (((RegVal >> 4) & 0x7) + 1); |
| 233 | |
| 234 | // The worst-case buffer size to request is for the SRAT table header, one |
| 235 | // entree for special region (base 640k block), two memory |
| 236 | // regions per node, and APIC entries for each core in the system. |
| 237 | tempVar_32 = (sizeof (CPU_SRAT_HEADER)) + (sizeof (CPU_SRAT_MEMORY_ENTRY)) |
| 238 | + ((UINT32) NodeCount * (2 * (sizeof (CPU_SRAT_MEMORY_ENTRY)) |
| 239 | + ((UINT32) GetActiveCoresInCurrentModule (StdHeader) * sizeof (CPU_SRAT_APIC_ENTRY)))); |
| 240 | |
| 241 | if (*SratPtr == NULL) { |
| 242 | // |
| 243 | // Allocate a buffer |
| 244 | // |
| 245 | AllocParams.RequestedBufferSize = tempVar_32; |
| 246 | AllocParams.BufferHandle = AMD_SRAT_INFO_BUFFER_HANDLE; |
| 247 | AllocParams.Persist = HEAP_SYSTEM_MEM; |
| 248 | |
| 249 | AGESA_TESTPOINT (TpProcCpuBeforeAllocateSratBuffer, StdHeader); |
| 250 | if (HeapAllocateBuffer (&AllocParams, StdHeader) != AGESA_SUCCESS) { |
| 251 | return AGESA_ERROR; |
| 252 | } |
| 253 | AGESA_TESTPOINT (TpProcCpuAfterAllocateSratBuffer, StdHeader); |
| 254 | |
| 255 | *SratPtr = AllocParams.BufferPtr; |
| 256 | } |
| 257 | |
| 258 | IDS_HDT_CONSOLE (CPU_TRACE, " SRAT is created\n"); |
| 259 | |
| 260 | CpuSratHeaderStructPtr = (CPU_SRAT_HEADER *) *SratPtr; |
| 261 | BufferPtr = (UINT8 *) *SratPtr; |
| 262 | |
| 263 | // Copy acpiSRATHeader -> data buffer |
| 264 | LibAmdMemCopy (*SratPtr, (VOID *) &CpuSratHdrStruct, (UINTN) (sizeof (CPU_SRAT_HEADER)), StdHeader); |
| 265 | |
| 266 | BufferPtr += sizeof (CPU_SRAT_HEADER); |
| 267 | |
| 268 | // Place all memory and IO affinity entries |
| 269 | NodeNum = 0; |
| 270 | PDomain = 0; |
| 271 | PDomainForBase640K = 0xFF; |
| 272 | ApicParams.StdHeader = *StdHeader; |
| 273 | while (NodeNum < NodeCount) { |
| 274 | GetSocketModuleOfNode ((UINT32) NodeNum, &Socket, &Module, StdHeader); |
| 275 | GetGivenModuleCoreRange (Socket, Module, &LowCore, &HighCore, StdHeader); |
| 276 | BufferPtr = FillMemoryForCurrentNode (&PDomain, &PDomainForBase640K, NodeNum, BufferPtr, StdHeader); |
| 277 | for (CoreNum = LowCore; CoreNum <= HighCore; CoreNum++) { |
| 278 | ApicParams.Socket = (UINT8) Socket; |
| 279 | ApicParams.Core = (UINT8) CoreNum; |
| 280 | AmdGetApicId (&ApicParams); |
| 281 | if (ApicParams.IsPresent) { |
| 282 | BufferPtr = MakeApicEntry (ApicParams.ApicAddress, PDomain, BufferPtr); |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | NodeNum++; |
| 287 | PDomain = NodeNum; |
| 288 | } |
| 289 | |
| 290 | // Store size in table (current buffer offset - buffer start offset) |
| 291 | CpuSratHeaderStructPtr->TableLength = (UINT32) (BufferPtr - (UINT8 *) CpuSratHeaderStructPtr); |
| 292 | |
| 293 | //Update SSDT header Checksum |
| 294 | ChecksumAcpiTable ((ACPI_TABLE_HEADER *) CpuSratHeaderStructPtr, StdHeader); |
| 295 | |
| 296 | return AGESA_SUCCESS; |
| 297 | } |
| 298 | |
| 299 | |
| 300 | /*---------------------------------------------------------------------------------------- |
| 301 | * L O C A L F U N C T I O N S |
| 302 | *---------------------------------------------------------------------------------------- |
| 303 | */ |
| 304 | |
| 305 | /*---------------------------------------------------------------------------------------*/ |
| 306 | /** |
| 307 | * |
| 308 | * This function will build Memory entry for current node. |
| 309 | * Note that we only create a memory affinity entry if we find one |
| 310 | * that matches the current node. This makes an easier to read table |
| 311 | * though it is not necessary. |
| 312 | * |
| 313 | * @param[in] PDomain Proximity Domain |
| 314 | * @param[in, out] PDomainForBase640K The PDomain for Base 640K |
| 315 | * @param[in] Node The number of Node |
| 316 | * @param[in, out] BufferLocPtr Point to the address of buffer |
| 317 | * @param[in, out] StdHeader Standard Head Pointer |
| 318 | * |
| 319 | * @retval UINT8 *(New buffer location ptr) |
| 320 | */ |
| 321 | UINT8 |
| 322 | STATIC |
| 323 | *FillMemoryForCurrentNode ( |
| 324 | IN UINT8 *PDomain, |
| 325 | IN OUT UINT8 *PDomainForBase640K, |
| 326 | IN UINT8 Node, |
| 327 | IN OUT UINT8 *BufferLocPtr, |
| 328 | IN OUT AMD_CONFIG_PARAMS *StdHeader |
| 329 | ) |
| 330 | { |
| 331 | UINT32 ValueLimit; |
| 332 | UINT32 ValueTOM; |
| 333 | BOOLEAN isModified; |
| 334 | UINT8 Domain; |
| 335 | UINT32 RegVal; |
| 336 | UINT32 DramLeng; |
| 337 | UINT32 DramBase; |
| 338 | UINT32 DramLimit; |
| 339 | UINT32 OffsetRegs; |
| 340 | PCI_ADDR PciAddress; |
| 341 | UINT64 MsrValue; |
| 342 | UINT32 TopOfMemoryAbove4Gb; |
| 343 | |
| 344 | Domain = *PDomain; |
| 345 | |
| 346 | PciAddress.Address.Segment = 0; |
| 347 | PciAddress.Address.Bus = 0; |
| 348 | PciAddress.Address.Device = LOW_NODE_DEVICEID; |
| 349 | PciAddress.Address.Function = FUNC_1; |
| 350 | |
| 351 | for (OffsetRegs = DRAMBase0; OffsetRegs < MMIOBase0; OffsetRegs += 8) { |
| 352 | isModified = FALSE; // FALSE means normal update procedure |
| 353 | // Get DRAM Base Address |
| 354 | PciAddress.Address.Register = OffsetRegs; |
| 355 | LibAmdPciRead (AccessWidth32, PciAddress, &DramBase, StdHeader); |
| 356 | if ((DramBase & 3) != 3) { |
| 357 | // 0:1 set if memory range enabled |
| 358 | // Not set, so we don't have an enabled range |
| 359 | continue; // Proceed to next Base register |
| 360 | } |
| 361 | |
| 362 | // Get DRAM Limit |
| 363 | PciAddress.Address.Register = OffsetRegs + 4; |
| 364 | LibAmdPciRead (AccessWidth32, PciAddress, &DramLimit, StdHeader); |
| 365 | if (DramLimit == 0xFFFFFFFF) { |
| 366 | // Node not installed(all FF's)? |
| 367 | continue; // Proceed to next Base register |
| 368 | } |
| 369 | |
| 370 | if ((DramLimit & 0xFF) != Node) { |
| 371 | // Check if Destination Node ID is current node |
| 372 | continue; // Proceed to next Base register |
| 373 | } |
| 374 | |
| 375 | // We only add an entry now if detected range belongs to current node/PDomain |
| 376 | PciAddress.Address.Register = OffsetRegs + 0x104; |
| 377 | LibAmdPciRead (AccessWidth32, PciAddress, &RegVal, StdHeader); |
| 378 | |
| 379 | DramLimit = (((RegVal & 0xFF) << 16) | (DramLimit >> 16)); // Get DRAM Limit addr [47:24] |
| 380 | DramLimit++; // Add 1 for potential length |
| 381 | DramLimit <<= 8; |
| 382 | |
| 383 | // Get DRAM Base Address |
| 384 | PciAddress.Address.Register = OffsetRegs + 0x100; |
| 385 | LibAmdPciRead (AccessWidth32, PciAddress, &RegVal, StdHeader); |
| 386 | DramBase = ((((RegVal & 0xFF) << 24) | (DramBase >> 8)) & 0xFFFFFF00); // Get DRAM Base Base value [47:24] |
| 387 | DramLeng = DramLimit - DramBase; // Subtract base from limit to get length |
| 388 | |
| 389 | // Leave hole for conventional memory (Less than 640K). It must be on CPU 0. |
| 390 | if (DramBase == 0) { |
| 391 | if (*PDomainForBase640K == 0xFF) { |
| 392 | // It is the first time that the range start at 0. |
| 393 | // If Yes, then Place 1MB memory gap and save Domain to PDomainForBase640K |
| 394 | BufferLocPtr = MakeMemEntry ( |
| 395 | Domain, |
| 396 | Node, |
| 397 | 0, // Base = 0 |
| 398 | 0xA0000 >> 16, // Put it into format used in DRAM regs.. |
| 399 | BufferLocPtr |
| 400 | ); |
| 401 | DramBase += 0x10; // Add 1MB, so range = 1MB to Top of Region |
| 402 | DramLeng -= 0x10; // Also subtract 1MB from the length |
| 403 | *PDomainForBase640K = Domain; // Save Domain number for memory Less than 640K |
| 404 | } else { |
| 405 | // If No, there are more than one memory range less than 640K, it should that |
| 406 | // node interleaving is enabled. All nodes have the same memory ranges |
| 407 | // and all cores in these nodes belong to the same domain. |
| 408 | *PDomain = *PDomainForBase640K; |
| 409 | return (BufferLocPtr); |
| 410 | } |
| 411 | } |
| 412 | LibAmdMsrRead (TOP_MEM, &MsrValue, StdHeader); |
| 413 | ValueTOM = (UINT32) MsrValue >> 16; // Save it in 39:24 format |
| 414 | ValueLimit = DramBase + DramLeng; // We need to know how large region is |
| 415 | |
| 416 | LibAmdMsrRead (SYS_CFG, &MsrValue, StdHeader); |
| 417 | if ((MsrValue & BIT21) != 0) { |
| 418 | LibAmdMsrRead (TOP_MEM2, &MsrValue, StdHeader); |
| 419 | TopOfMemoryAbove4Gb = (UINT32) (MsrValue >> 16); // Save it in 47:16 format |
| 420 | } else { |
| 421 | TopOfMemoryAbove4Gb = 0xFFFFFFFF; |
| 422 | } |
| 423 | |
| 424 | // SPECIAL CASES: |
| 425 | // |
| 426 | // Several conditions require that we process the values of the memory range differently. |
| 427 | // Here are descriptions of the corner cases. |
| 428 | // |
| 429 | // 1. TRUNCATE LOW - Memory range starts below TOM, ends in TOM (memory hole). For this case, |
| 430 | // the range must be truncated to end at TOM. |
| 431 | // ******************************* ******************************* |
| 432 | // * * * -> * * |
| 433 | // ******************************* ******************************* |
| 434 | // 2 TOM 4 2 TOM |
| 435 | // |
| 436 | // 2. TRUNCATE HIGH - Memory range starts below 4GB, ends above 4GB. This is handled by changing the |
| 437 | // start base to 4GB. |
| 438 | // **************** ********** |
| 439 | // * * * -> * * |
| 440 | // **************** ********** |
| 441 | // TOM 3.8 4 6 TOM 3.8 4 6 |
| 442 | // |
| 443 | // 3. Memory range starts below TOM, ends above 4GB. For this case, the range must be truncated |
| 444 | // to end at TOM. Note that this scenario creates two ranges, as the second comparison below |
| 445 | // will find that it ends above 4GB since base and limit have been restored after first truncation, |
| 446 | // and a second range will be written based at 4GB ending at original end address. |
| 447 | // ******************************* **************** ********** |
| 448 | // * * * * -> * * * * |
| 449 | // ******************************* **************** ********** |
| 450 | // 2 TOM 4 6 2 TOM 4 6 |
| 451 | // |
| 452 | // 4. Memory range starts above TOM, ends below or equal to 4GB. This invalid range should simply |
| 453 | // be ignored. |
| 454 | // ******* |
| 455 | // * * -> < NULL > |
| 456 | // ******* |
| 457 | // TOM 3.8 4 |
| 458 | // |
| 459 | // 5. Memory range starts below TOM2, and ends beyond TOM2. This range must be truncated to TOM2. |
| 460 | // ************************ ******************************* |
| 461 | // * * * -> * * |
| 462 | // ************************ ******************************* |
| 463 | // 768 TOM2 1024 768 TOM2 |
| 464 | // |
| 465 | // 6. Memory range starts above TOM2. This invalid range should simply be ignored. |
| 466 | // ******************** |
| 467 | // * * -> < NULL > |
| 468 | // ******************** |
| 469 | // TOM2 1024 1280 |
| 470 | |
| 471 | if (((DramBase < ValueTOM) && (ValueLimit <= FOURGB) && (ValueLimit > ValueTOM)) |
| 472 | || ((DramBase < ValueTOM) && (ValueLimit > FOURGB))) { |
| 473 | // TRUNCATE LOW!!! Shrink entry below TOM... |
| 474 | // Base = DramBase, Size = TOM - DramBase |
| 475 | BufferLocPtr = MakeMemEntry (Domain, Node, DramBase, (ValueTOM - DramBase), BufferLocPtr); |
| 476 | isModified = TRUE; |
| 477 | } |
| 478 | |
| 479 | if ((ValueLimit > FOURGB) && (DramBase < FOURGB)) { |
| 480 | // TRUNCATE HIGH!!! Shrink entry above 4GB... |
| 481 | // Size = Base + Size - 4GB, Base = 4GB |
| 482 | BufferLocPtr = MakeMemEntry (Domain, Node, FOURGB, (DramLeng + DramBase - FOURGB), BufferLocPtr); |
| 483 | isModified = TRUE; |
| 484 | } |
| 485 | |
| 486 | if ((DramBase >= ValueTOM) && (ValueLimit <= FOURGB)) { |
| 487 | // IGNORE!!! Entry located entirely within memory hole |
| 488 | isModified = TRUE; |
| 489 | } |
| 490 | |
| 491 | if ((DramBase < TopOfMemoryAbove4Gb) && (ValueLimit > TopOfMemoryAbove4Gb)) { |
| 492 | // Truncate to TOM2 |
| 493 | // Base = DramBase, Size = TOM2 - DramBase |
| 494 | BufferLocPtr = MakeMemEntry (Domain, Node, DramBase, (TopOfMemoryAbove4Gb - DramBase), BufferLocPtr); |
| 495 | isModified = TRUE; |
| 496 | } |
| 497 | |
| 498 | if (DramBase >= TopOfMemoryAbove4Gb) { |
| 499 | // IGNORE!!! Entry located entirely above TOM2 |
| 500 | isModified = TRUE; |
| 501 | } |
| 502 | |
| 503 | // If special range(isModified), we are done. |
| 504 | // If not, finally write the memory entry. |
| 505 | if (isModified == FALSE) { |
| 506 | // Finally write the memory entry. |
| 507 | BufferLocPtr = MakeMemEntry (Domain, Node, DramBase, DramLeng, BufferLocPtr); |
| 508 | } |
| 509 | |
| 510 | } // for ( OffsetRegs = DRAMBase0; ... ) |
| 511 | |
| 512 | return (BufferLocPtr); |
| 513 | } // FillMemoryForCurrentNode() |
| 514 | |
| 515 | |
| 516 | /*---------------------------------------------------------------------------------------*/ |
| 517 | /** |
| 518 | * This function will add APIC entry. |
| 519 | * |
| 520 | * @param[in] ApicId APIC ID number |
| 521 | * @param[in] Domain Domain number |
| 522 | * @param[in] BufferLocPtr Point to the address of buffer |
| 523 | * |
| 524 | * @retval UINT8 *(New buffer location ptr) |
| 525 | */ |
| 526 | UINT8 |
| 527 | STATIC |
| 528 | *MakeApicEntry ( |
| 529 | IN UINT8 ApicId, |
| 530 | IN UINT8 Domain, |
| 531 | IN UINT8 *BufferLocPtr |
| 532 | ) |
| 533 | { |
| 534 | CPU_SRAT_APIC_ENTRY *psSratApicEntry; |
| 535 | UINT8 ReservedBytes; |
| 536 | |
| 537 | psSratApicEntry = (CPU_SRAT_APIC_ENTRY *)BufferLocPtr; |
| 538 | |
| 539 | psSratApicEntry->Type = AE_APIC; |
| 540 | psSratApicEntry->Length = (UINT8)sizeof (CPU_SRAT_APIC_ENTRY); |
| 541 | psSratApicEntry->Domain = Domain; |
| 542 | psSratApicEntry->ApicId = ApicId; |
| 543 | psSratApicEntry->Flags = ENABLED; |
| 544 | psSratApicEntry->LSApicEid = 0; |
| 545 | for (ReservedBytes = 0; ReservedBytes < (UINT8)sizeof (psSratApicEntry->Reserved); ReservedBytes++) { |
| 546 | psSratApicEntry->Reserved[ReservedBytes] = 0; |
| 547 | } |
| 548 | return (BufferLocPtr + (UINT8)sizeof (CPU_SRAT_APIC_ENTRY)); |
| 549 | } // MakeApicEntry |
| 550 | |
| 551 | |
| 552 | /*---------------------------------------------------------------------------------------*/ |
| 553 | /** |
| 554 | * |
| 555 | * This function will add Memory entry. |
| 556 | * |
| 557 | * Parameters: |
| 558 | * @param[in] PDomain Proximity Domain |
| 559 | * @param[in] Node The number of Node |
| 560 | * @param[in] Base Memory Base |
| 561 | * @param[in] Size Memory Size |
| 562 | * @param[in] BufferLocPtr Point to the address of buffer |
| 563 | * |
| 564 | * @retval UINT8 * (new buffer location ptr) |
| 565 | */ |
| 566 | UINT8 |
| 567 | STATIC |
| 568 | *MakeMemEntry ( |
| 569 | IN UINT8 PDomain, |
| 570 | IN UINT8 Node, |
| 571 | IN UINT32 Base, |
| 572 | IN UINT32 Size, |
| 573 | IN UINT8 *BufferLocPtr |
| 574 | ) |
| 575 | { |
| 576 | CPU_SRAT_MEMORY_ENTRY *psSratMemEntry; |
| 577 | UINT8 ReservedBytes; |
| 578 | |
| 579 | psSratMemEntry = (CPU_SRAT_MEMORY_ENTRY *)BufferLocPtr; |
| 580 | |
| 581 | psSratMemEntry->Type = AE_MEMORY; // [0] = Memory Entry |
| 582 | psSratMemEntry->Length = (UINT8)sizeof (CPU_SRAT_MEMORY_ENTRY); // [1] = 40 |
| 583 | psSratMemEntry->Domain = PDomain; // [2] = Proximity Domain |
| 584 | |
| 585 | // [6-7] = Reserved |
| 586 | for (ReservedBytes = 0; ReservedBytes < (UINT8)sizeof (psSratMemEntry->Reserved1); ReservedBytes++) { |
| 587 | psSratMemEntry->Reserved1[ReservedBytes] = 0; |
| 588 | } |
| 589 | |
| 590 | // [8-11] = Keep 31:0 of address only -> Base Addr Low |
| 591 | psSratMemEntry->BaseAddrLow = Base << 16; |
| 592 | |
| 593 | // [12-15] = Keep 39:32 of address only -> Base Addr High |
| 594 | psSratMemEntry->BaseAddrHigh = Base >> 16; |
| 595 | |
| 596 | // [16-19] = Keep 31:0 of address only -> Length Low |
| 597 | psSratMemEntry->LengthAddrLow = Size << 16; |
| 598 | |
| 599 | // [20-23] = Keep 39:32 of address only -> Length High |
| 600 | psSratMemEntry->LengthAddrHigh = Size >> 16; |
| 601 | |
| 602 | // [24-27] = Reserved |
| 603 | for (ReservedBytes = 0; ReservedBytes < (UINT8)sizeof (psSratMemEntry->Reserved2); ReservedBytes++) { |
| 604 | psSratMemEntry->Reserved2[ReservedBytes] = 0; |
| 605 | } |
| 606 | |
| 607 | // [28-31] = Flags |
| 608 | psSratMemEntry->Flags = ENABLED; |
| 609 | |
| 610 | // [32-40] = Reserved |
| 611 | for (ReservedBytes = 0; ReservedBytes < (UINT8)sizeof (psSratMemEntry->Reserved3); ReservedBytes++) { |
| 612 | psSratMemEntry->Reserved3[ReservedBytes] = 0; |
| 613 | } |
| 614 | return (BufferLocPtr + (UINT8)sizeof (CPU_SRAT_MEMORY_ENTRY)); |
| 615 | } // MakeMemEntry() |
| 616 | |