1 /** @file 2 QuarkNcSocId module initialization module 3 4 Copyright (c) 2013-2015 Intel Corporation. 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 #include "CommonHeader.h" 16 17 #include "LegacyRegion.h" 18 #include "DxeQNCSmbus.h" 19 20 #include "QNCInit.h" 21 22 // 23 // Definitions 24 // 25 #define QNC_RESERVED_ITEM_IO 0 26 #define QNC_RESERVED_ITEM_MEMORYIO 1 27 #define DXE_DEVICE_DISABLED 0 28 #define DXE_DEVICE_ENABLED 1 29 30 typedef struct _QNC_SPACE_TABLE_ITEM { 31 UINTN IoOrMemory; 32 UINTN Type; 33 EFI_PHYSICAL_ADDRESS BaseAddress; 34 UINT64 Length; 35 UINTN Alignment; 36 BOOLEAN RuntimeOrNot; 37 } QNC_SPACE_TABLE_ITEM; 38 39 typedef struct { 40 ACPI_CPU_DATA AcpuCpuData; 41 MTRR_SETTINGS MtrrTable; 42 IA32_DESCRIPTOR GdtrProfile; 43 IA32_DESCRIPTOR IdtrProfile; 44 CPU_REGISTER_TABLE RegisterTable; 45 CPU_REGISTER_TABLE PreSmmInitRegisterTable; 46 } ACPI_CPU_DATA_EX; 47 48 // 49 // Spaces to be reserved in GCD 50 // Expand it to add more 51 // 52 const QNC_SPACE_TABLE_ITEM mQNCReservedSpaceTable[] = { 53 { 54 QNC_RESERVED_ITEM_MEMORYIO, 55 EfiGcdMemoryTypeMemoryMappedIo, 56 FixedPcdGet64 (PcdIoApicBaseAddress), 57 FixedPcdGet64 (PcdIoApicSize), 58 0, 59 FALSE 60 }, 61 { 62 QNC_RESERVED_ITEM_MEMORYIO, 63 EfiGcdMemoryTypeMemoryMappedIo, 64 FixedPcdGet64 (PcdHpetBaseAddress), 65 FixedPcdGet64 (PcdHpetSize), 66 0, 67 FALSE 68 } 69 }; 70 71 // 72 // Global variable for ImageHandle of QNCInit driver 73 // 74 EFI_HANDLE gQNCInitImageHandle; 75 QNC_DEVICE_ENABLES mQNCDeviceEnables; 76 77 78 VOID 79 QNCInitializeResource ( 80 VOID 81 ); 82 83 EFI_STATUS 84 InitializeQNCPolicy ( 85 VOID 86 ); 87 88 /** 89 Allocate EfiACPIMemoryNVS below 4G memory address. 90 91 This function allocates EfiACPIMemoryNVS below 4G memory address. 92 93 @param Size Size of memory to allocate. 94 95 @return Allocated address for output. 96 97 **/ 98 VOID * 99 AllocateAcpiNvsMemoryBelow4G ( 100 IN UINTN Size 101 ) 102 { 103 UINTN Pages; 104 EFI_PHYSICAL_ADDRESS Address; 105 EFI_STATUS Status; 106 VOID* Buffer; 107 108 Pages = EFI_SIZE_TO_PAGES (Size); 109 Address = 0xffffffff; 110 111 Status = gBS->AllocatePages ( 112 AllocateMaxAddress, 113 EfiACPIMemoryNVS, 114 Pages, 115 &Address 116 ); 117 if (EFI_ERROR (Status)) { 118 return NULL; 119 } 120 121 Buffer = (VOID *) (UINTN) Address; 122 ZeroMem (Buffer, Size); 123 124 return Buffer; 125 } 126 127 /** 128 Prepare ACPI NVS memory below 4G memory for use of S3 resume. 129 130 This function allocates ACPI NVS memory below 4G memory for use of S3 resume, 131 and saves data into the memory region. 132 133 **/ 134 VOID 135 SaveCpuS3Data ( 136 VOID 137 ) 138 { 139 EFI_STATUS Status; 140 ACPI_CPU_DATA_EX *AcpiCpuDataEx; 141 ACPI_CPU_DATA *AcpiCpuData; 142 UINTN GdtSize; 143 UINTN IdtSize; 144 VOID *Gdt; 145 VOID *Idt; 146 147 // 148 // Allocate ACPI NVS memory below 4G memory for use of S3 resume. 149 // 150 AcpiCpuDataEx = AllocateAcpiNvsMemoryBelow4G (sizeof (ACPI_CPU_DATA_EX)); 151 AcpiCpuData = &AcpiCpuDataEx->AcpuCpuData; 152 153 // 154 // 155 // 156 AcpiCpuData->NumberOfCpus = 1; 157 AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize); 158 AcpiCpuData->ApMachineCheckHandlerBase = 0; 159 AcpiCpuData->ApMachineCheckHandlerSize = 0; 160 AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->GdtrProfile; 161 AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->IdtrProfile; 162 AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->MtrrTable; 163 AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->RegisterTable; 164 AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->PreSmmInitRegisterTable; 165 166 // 167 // Allocate stack space for all CPUs 168 // 169 AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateAcpiNvsMemoryBelow4G (AcpiCpuData->NumberOfCpus * AcpiCpuData->StackSize); 170 171 // 172 // Get MTRR settings from currently executing CPU 173 // 174 MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable); 175 176 // 177 // Get the BSP's data of GDT and IDT 178 // 179 AsmReadGdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->GdtrProfile); 180 AsmReadIdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->IdtrProfile); 181 182 // 183 // Allocate GDT and IDT in ACPI NVS and copy in current GDT and IDT contents 184 // 185 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1; 186 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1; 187 Gdt = AllocateAcpiNvsMemoryBelow4G (GdtSize + IdtSize); 188 Idt = (VOID *)((UINTN)Gdt + GdtSize); 189 CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize); 190 CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize); 191 AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt; 192 AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt; 193 194 // 195 // No RegisterTable entries 196 // 197 AcpiCpuDataEx->RegisterTable.TableLength = 0; 198 199 // 200 // No PreSmmInitRegisterTable entries 201 // 202 AcpiCpuDataEx->PreSmmInitRegisterTable.TableLength = 0; 203 204 // 205 // Set the base address of CPU S3 data to PcdCpuS3DataAddress 206 // 207 Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData); 208 ASSERT_EFI_ERROR (Status); 209 } 210 211 /** 212 The entry function for QNCInit driver. 213 214 This function just call initialization function for PciHostBridge, 215 LegacyRegion and QNCSmmAccess module. 216 217 @param ImageHandle The driver image handle for GmchInit driver 218 @param SystemTable The pointer to System Table 219 220 @retval EFI_SUCCESS Success to initialize every module for GMCH driver. 221 @return EFI_STATUS The status of initialization work. 222 223 **/ 224 EFI_STATUS 225 EFIAPI 226 QNCInit ( 227 IN EFI_HANDLE ImageHandle, 228 IN EFI_SYSTEM_TABLE *SystemTable 229 ) 230 { 231 EFI_STATUS Status; 232 233 S3BootScriptSaveInformationAsciiString ( 234 "QNCInitDxeEntryBegin" 235 ); 236 237 gQNCInitImageHandle = ImageHandle; 238 239 mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables); 240 241 242 // 243 // Initialize PCIE root ports 244 // 245 Status = QncInitRootPorts (); 246 if (EFI_ERROR (Status)) { 247 DEBUG ((EFI_D_ERROR, "QNC Root Port initialization is failed!\n")); 248 return Status; 249 } 250 251 Status = LegacyRegionInit (); 252 if (EFI_ERROR (Status)) { 253 DEBUG ((EFI_D_ERROR, "QNC LegacyRegion initialization is failed!\n")); 254 return Status; 255 } 256 257 258 Status = InitializeQNCPolicy (); 259 if (EFI_ERROR (Status)) { 260 DEBUG ((EFI_D_ERROR, "QNC Policy initialization is failed!\n")); 261 return Status; 262 } 263 264 Status = InitializeQNCSmbus (ImageHandle,SystemTable); 265 if (EFI_ERROR (Status)) { 266 DEBUG ((EFI_D_ERROR, "QNC Smbus driver is failed!\n")); 267 return Status; 268 } 269 270 QNCInitializeResource (); 271 272 SaveCpuS3Data (); 273 274 S3BootScriptSaveInformationAsciiString ( 275 "QNCInitDxeEntryEnd" 276 ); 277 278 return EFI_SUCCESS; 279 } 280 281 282 /** 283 Reserve I/O or memory space in GCD 284 285 @param IoOrMemory Switch of I/O or memory. 286 @param GcdType Type of the space. 287 @param BaseAddress Base address of the space. 288 @param Length Length of the space. 289 @param Alignment Align with 2^Alignment 290 @param RuntimeOrNot For runtime usage or not 291 @param ImageHandle Handle for the image of this driver. 292 293 @retval EFI_SUCCESS Reserve successful 294 **/ 295 EFI_STATUS 296 QNCReserveSpaceInGcd( 297 IN UINTN IoOrMemory, 298 IN UINTN GcdType, 299 IN EFI_PHYSICAL_ADDRESS BaseAddress, 300 IN UINT64 Length, 301 IN UINTN Alignment, 302 IN BOOLEAN RuntimeOrNot, 303 IN EFI_HANDLE ImageHandle 304 ) 305 { 306 EFI_STATUS Status; 307 308 if (IoOrMemory == QNC_RESERVED_ITEM_MEMORYIO) { 309 Status = gDS->AddMemorySpace ( 310 GcdType, 311 BaseAddress, 312 Length, 313 EFI_MEMORY_UC 314 ); 315 if (EFI_ERROR (Status)) { 316 DEBUG (( 317 EFI_D_ERROR, 318 "Failed to add memory space :0x%x 0x%x\n", 319 BaseAddress, 320 Length 321 )); 322 } 323 ASSERT_EFI_ERROR (Status); 324 Status = gDS->AllocateMemorySpace ( 325 EfiGcdAllocateAddress, 326 GcdType, 327 Alignment, 328 Length, 329 &BaseAddress, 330 ImageHandle, 331 NULL 332 ); 333 ASSERT_EFI_ERROR (Status); 334 if (RuntimeOrNot) { 335 Status = gDS->SetMemorySpaceAttributes ( 336 BaseAddress, 337 Length, 338 EFI_MEMORY_RUNTIME | EFI_MEMORY_UC 339 ); 340 ASSERT_EFI_ERROR (Status); 341 } 342 } else { 343 Status = gDS->AddIoSpace ( 344 GcdType, 345 BaseAddress, 346 Length 347 ); 348 ASSERT_EFI_ERROR (Status); 349 Status = gDS->AllocateIoSpace ( 350 EfiGcdAllocateAddress, 351 GcdType, 352 Alignment, 353 Length, 354 &BaseAddress, 355 ImageHandle, 356 NULL 357 ); 358 ASSERT_EFI_ERROR (Status); 359 } 360 return Status; 361 } 362 363 364 /** 365 Initialize the memory and io resource which belong to QNC. 366 1) Report and allocate all BAR's memory to GCD. 367 2) Report PCI memory and I/O space to GCD. 368 3) Set memory attribute for <1M memory space. 369 **/ 370 VOID 371 QNCInitializeResource ( 372 ) 373 { 374 EFI_PHYSICAL_ADDRESS BaseAddress; 375 EFI_STATUS Status; 376 UINT64 ExtraRegionLength; 377 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; 378 UINTN Index; 379 380 // Report TSEG range 381 // This range maybe has been reportted in PEI phase via Resource Hob. 382 // 383 QNCGetTSEGMemoryRange (&BaseAddress, &ExtraRegionLength); 384 if (ExtraRegionLength != 0) { 385 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &Descriptor); 386 if (Status == EFI_NOT_FOUND) { 387 Status = gDS->AddMemorySpace ( 388 EfiGcdMemoryTypeReserved, 389 BaseAddress, 390 ExtraRegionLength, 391 EFI_MEMORY_UC 392 ); 393 } 394 } 395 396 // 397 // < 1M resource setting. The memory ranges <1M has been added into GCD via 398 // resource hob produced by PEI phase. Here will set memory attribute of these 399 // ranges for DXE phase. 400 // 401 402 // 403 // Dos Area (0 ~ 0x9FFFFh) 404 // 405 Status = gDS->GetMemorySpaceDescriptor (0, &Descriptor); 406 DEBUG (( 407 EFI_D_INFO, 408 "DOS Area Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n", 409 Descriptor.BaseAddress, 410 Descriptor.Length, 411 Descriptor.Attributes 412 )); 413 ASSERT_EFI_ERROR (Status); 414 Status = gDS->SetMemorySpaceAttributes( 415 0, 416 0xA0000, 417 EFI_MEMORY_WB 418 ); 419 ASSERT_EFI_ERROR (Status); 420 421 // 422 // Default SMRAM UnCachable until SMBASE relocated. 423 // 424 Status = gDS->SetMemorySpaceAttributes( 425 0x30000, 426 0x10000, 427 EFI_MEMORY_UC 428 ); 429 ASSERT_EFI_ERROR (Status); 430 431 // 432 // Default SMM ABSEG area. (0xA0000 ~ 0xBFFFF) 433 // 434 Status = gDS->GetMemorySpaceDescriptor (0xA0000, &Descriptor); 435 DEBUG (( 436 EFI_D_INFO, 437 "ABSEG Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n", 438 Descriptor.BaseAddress, 439 Descriptor.Length, 440 Descriptor.Attributes 441 )); 442 ASSERT_EFI_ERROR (Status); 443 Status = gDS->SetMemorySpaceAttributes( 444 0xA0000, 445 0x20000, 446 EFI_MEMORY_UC 447 ); 448 ASSERT_EFI_ERROR (Status); 449 450 // 451 // Expansion BIOS area. 452 // 453 Status = gDS->GetMemorySpaceDescriptor (0xC0000, &Descriptor); 454 DEBUG (( 455 EFI_D_INFO, 456 "Memory base = 0x%x, length = 0x%x, attribute = 0x%x\n", 457 Descriptor.BaseAddress, 458 Descriptor.Length, 459 Descriptor.Attributes 460 )); 461 ASSERT_EFI_ERROR (Status); 462 Status = gDS->SetMemorySpaceAttributes( 463 0xC0000, 464 0x30000, 465 EFI_MEMORY_UC 466 ); 467 ASSERT_EFI_ERROR (Status); 468 469 // 470 // Report other IO resources from mQNCReservedSpaceTable in GCD 471 // 472 for (Index = 0; Index < sizeof (mQNCReservedSpaceTable) / sizeof (QNC_SPACE_TABLE_ITEM); Index++) { 473 Status = QNCReserveSpaceInGcd ( 474 mQNCReservedSpaceTable[Index].IoOrMemory, 475 mQNCReservedSpaceTable[Index].Type, 476 mQNCReservedSpaceTable[Index].BaseAddress, 477 mQNCReservedSpaceTable[Index].Length, 478 mQNCReservedSpaceTable[Index].Alignment, 479 mQNCReservedSpaceTable[Index].RuntimeOrNot, 480 gQNCInitImageHandle 481 ); 482 ASSERT_EFI_ERROR (Status); 483 } 484 485 // 486 // Report unused PCIe config space as reserved. 487 // 488 if (PcdGet64 (PcdPciExpressSize) < SIZE_256MB) { 489 Status = QNCReserveSpaceInGcd ( 490 QNC_RESERVED_ITEM_MEMORYIO, 491 EfiGcdMemoryTypeMemoryMappedIo, 492 (PcdGet64(PcdPciExpressBaseAddress) + PcdGet64(PcdPciExpressSize)), 493 (SIZE_256MB - PcdGet64(PcdPciExpressSize)), 494 0, 495 FALSE, 496 gQNCInitImageHandle 497 ); 498 ASSERT_EFI_ERROR (Status); 499 } 500 } 501 502 /** 503 Use the platform PCD to initialize devices in the QNC 504 505 @param ImageHandle Handle for the image of this driver. 506 @retval EFI_SUCCESS Initialize successful 507 **/ 508 EFI_STATUS 509 InitializeQNCPolicy ( 510 ) 511 { 512 UINT32 PciD31F0RegBase; // LPC 513 514 PciD31F0RegBase = PciDeviceMmBase (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC); 515 516 // 517 // Disable for smbus 518 // 519 if (mQNCDeviceEnables.Bits.Smbus == DXE_DEVICE_DISABLED) { 520 S3MmioAnd32 (PciD31F0RegBase + R_QNC_LPC_SMBUS_BASE, (~B_QNC_LPC_SMBUS_BASE_EN)); 521 } 522 523 return EFI_SUCCESS; 524 } 525