1 /*++ @file 2 Emu driver to produce CPU Architectural Protocol. 3 4 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> 5 Portions copyright (c) 2011 - 2012, Apple Inc. All rights reserved. 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 16 #include "CpuDriver.h" 17 18 UINT64 mTimerPeriod; 19 20 CPU_ARCH_PROTOCOL_PRIVATE mCpuTemplate = { 21 CPU_ARCH_PROT_PRIVATE_SIGNATURE, 22 NULL, 23 { 24 EmuFlushCpuDataCache, 25 EmuEnableInterrupt, 26 EmuDisableInterrupt, 27 EmuGetInterruptState, 28 EmuInit, 29 EmuRegisterInterruptHandler, 30 EmuGetTimerValue, 31 EmuSetMemoryAttributes, 32 0, 33 4 34 }, 35 { 36 { 37 CpuMemoryServiceRead, 38 CpuMemoryServiceWrite 39 }, 40 { 41 CpuIoServiceRead, 42 CpuIoServiceWrite 43 } 44 }, 45 TRUE 46 }; 47 48 #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100 49 50 SMBIOS_TABLE_TYPE4 mCpuSmbiosType4 = { 51 { EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION, sizeof (SMBIOS_TABLE_TYPE4), 0}, 52 1, // Socket String 53 ProcessorOther, // ProcessorType; ///< The enumeration value from PROCESSOR_TYPE_DATA. 54 ProcessorFamilyOther, // ProcessorFamily; ///< The enumeration value from PROCESSOR_FAMILY_DATA. 55 2, // ProcessorManufacture String; 56 { // ProcessorId; 57 { // PROCESSOR_SIGNATURE 58 0, // ProcessorSteppingId:4; 59 0, // ProcessorModel: 4; 60 0, // ProcessorFamily: 4; 61 0, // ProcessorType: 2; 62 0, // ProcessorReserved1: 2; 63 0, // ProcessorXModel: 4; 64 0, // ProcessorXFamily: 8; 65 0, // ProcessorReserved2: 4; 66 }, 67 { // PROCESSOR_FEATURE_FLAGS 68 0, // ProcessorFpu :1; 69 0, // ProcessorVme :1; 70 0, // ProcessorDe :1; 71 0, // ProcessorPse :1; 72 0, // ProcessorTsc :1; 73 0, // ProcessorMsr :1; 74 0, // ProcessorPae :1; 75 0, // ProcessorMce :1; 76 0, // ProcessorCx8 :1; 77 0, // ProcessorApic :1; 78 0, // ProcessorReserved1 :1; 79 0, // ProcessorSep :1; 80 0, // ProcessorMtrr :1; 81 0, // ProcessorPge :1; 82 0, // ProcessorMca :1; 83 0, // ProcessorCmov :1; 84 0, // ProcessorPat :1; 85 0, // ProcessorPse36 :1; 86 0, // ProcessorPsn :1; 87 0, // ProcessorClfsh :1; 88 0, // ProcessorReserved2 :1; 89 0, // ProcessorDs :1; 90 0, // ProcessorAcpi :1; 91 0, // ProcessorMmx :1; 92 0, // ProcessorFxsr :1; 93 0, // ProcessorSse :1; 94 0, // ProcessorSse2 :1; 95 0, // ProcessorSs :1; 96 0, // ProcessorReserved3 :1; 97 0, // ProcessorTm :1; 98 0, // ProcessorReserved4 :2; 99 } 100 }, 101 3, // ProcessorVersion String; 102 { // Voltage; 103 1, // ProcessorVoltageCapability5V :1; 104 1, // ProcessorVoltageCapability3_3V :1; 105 1, // ProcessorVoltageCapability2_9V :1; 106 0, // ProcessorVoltageCapabilityReserved :1; ///< Bit 3, must be zero. 107 0, // ProcessorVoltageReserved :3; ///< Bits 4-6, must be zero. 108 0 // ProcessorVoltageIndicateLegacy :1; 109 }, 110 0, // ExternalClock; 111 0, // MaxSpeed; 112 0, // CurrentSpeed; 113 0x41, // Status; 114 ProcessorUpgradeOther, // ProcessorUpgrade; ///< The enumeration value from PROCESSOR_UPGRADE. 115 0, // L1CacheHandle; 116 0, // L2CacheHandle; 117 0, // L3CacheHandle; 118 4, // SerialNumber; 119 5, // AssetTag; 120 6, // PartNumber; 121 0, // CoreCount; 122 0, // EnabledCoreCount; 123 0, // ThreadCount; 124 0, // ProcessorCharacteristics; 125 0, // ProcessorFamily2; 126 }; 127 128 CHAR8 *mCpuSmbiosType4Strings[] = { 129 "Socket", 130 "http://www.tianocore.org/edk2/", 131 "Emulated Processor", 132 "1.0", 133 "1.0", 134 "1.0", 135 NULL 136 }; 137 138 139 /** 140 Create SMBIOS record. 141 142 Converts a fixed SMBIOS structure and an array of pointers to strings into 143 an SMBIOS record where the strings are cat'ed on the end of the fixed record 144 and terminated via a double NULL and add to SMBIOS table. 145 146 SMBIOS_TABLE_TYPE32 gSmbiosType12 = { 147 { EFI_SMBIOS_TYPE_SYSTEM_CONFIGURATION_OPTIONS, sizeof (SMBIOS_TABLE_TYPE12), 0 }, 148 1 // StringCount 149 }; 150 CHAR8 *gSmbiosType12Strings[] = { 151 "Not Found", 152 NULL 153 }; 154 155 ... 156 LogSmbiosData ( 157 (EFI_SMBIOS_TABLE_HEADER*)&gSmbiosType12, 158 gSmbiosType12Strings 159 ); 160 161 @param Template Fixed SMBIOS structure, required. 162 @param StringArray Array of strings to convert to an SMBIOS string pack. 163 NULL is OK. 164 165 **/ 166 EFI_STATUS 167 LogSmbiosData ( 168 IN EFI_SMBIOS_TABLE_HEADER *Template, 169 IN CHAR8 **StringPack 170 ) 171 { 172 EFI_STATUS Status; 173 EFI_SMBIOS_PROTOCOL *Smbios; 174 EFI_SMBIOS_HANDLE SmbiosHandle; 175 EFI_SMBIOS_TABLE_HEADER *Record; 176 UINTN Index; 177 UINTN StringSize; 178 UINTN Size; 179 CHAR8 *Str; 180 181 // 182 // Locate Smbios protocol. 183 // 184 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios); 185 if (EFI_ERROR (Status)) { 186 return Status; 187 } 188 189 // Calculate the size of the fixed record and optional string pack 190 Size = Template->Length; 191 if (StringPack == NULL) { 192 // At least a double null is required 193 Size += 2; 194 } else { 195 for (Index = 0; StringPack[Index] != NULL; Index++) { 196 StringSize = AsciiStrSize (StringPack[Index]); 197 Size += StringSize; 198 } 199 if (StringPack[0] == NULL) { 200 // At least a double null is required 201 Size += 1; 202 } 203 // Don't forget the terminating double null 204 Size += 1; 205 } 206 207 // Copy over Template 208 Record = (EFI_SMBIOS_TABLE_HEADER *)AllocateZeroPool (Size); 209 if (Record == NULL) { 210 return EFI_OUT_OF_RESOURCES; 211 } 212 CopyMem (Record, Template, Template->Length); 213 214 // Append string pack 215 Str = ((CHAR8 *)Record) + Record->Length; 216 for (Index = 0; StringPack[Index] != NULL; Index++) { 217 StringSize = AsciiStrSize (StringPack[Index]); 218 CopyMem (Str, StringPack[Index], StringSize); 219 Str += StringSize; 220 } 221 *Str = 0; 222 223 SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; 224 Status = Smbios->Add ( 225 Smbios, 226 gImageHandle, 227 &SmbiosHandle, 228 Record 229 ); 230 ASSERT_EFI_ERROR (Status); 231 232 FreePool (Record); 233 return Status; 234 } 235 236 237 238 239 VOID 240 CpuUpdateSmbios ( 241 IN UINTN MaxCpus 242 ) 243 { 244 mCpuSmbiosType4.CoreCount = (UINT8) MaxCpus; 245 mCpuSmbiosType4.EnabledCoreCount = (UINT8) MaxCpus; 246 mCpuSmbiosType4.ThreadCount = (UINT8) MaxCpus; 247 248 LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mCpuSmbiosType4, mCpuSmbiosType4Strings); 249 } 250 251 252 // 253 // Service routines for the driver 254 // 255 EFI_STATUS 256 EFIAPI 257 EmuFlushCpuDataCache ( 258 IN EFI_CPU_ARCH_PROTOCOL *This, 259 IN EFI_PHYSICAL_ADDRESS Start, 260 IN UINT64 Length, 261 IN EFI_CPU_FLUSH_TYPE FlushType 262 ) 263 { 264 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { 265 // 266 // Only WB flush is supported. We actually need do nothing on Emu emulator 267 // environment. Classify this to follow EFI spec 268 // 269 return EFI_SUCCESS; 270 } 271 // 272 // Other flush types are not supported by Emu emulator 273 // 274 return EFI_UNSUPPORTED; 275 } 276 277 EFI_STATUS 278 EFIAPI 279 EmuEnableInterrupt ( 280 IN EFI_CPU_ARCH_PROTOCOL *This 281 ) 282 { 283 CPU_ARCH_PROTOCOL_PRIVATE *Private; 284 285 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); 286 Private->InterruptState = TRUE; 287 gEmuThunk->EnableInterrupt (); 288 return EFI_SUCCESS; 289 } 290 291 EFI_STATUS 292 EFIAPI 293 EmuDisableInterrupt ( 294 IN EFI_CPU_ARCH_PROTOCOL *This 295 ) 296 { 297 CPU_ARCH_PROTOCOL_PRIVATE *Private; 298 299 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); 300 Private->InterruptState = FALSE; 301 gEmuThunk->DisableInterrupt (); 302 return EFI_SUCCESS; 303 } 304 305 EFI_STATUS 306 EFIAPI 307 EmuGetInterruptState ( 308 IN EFI_CPU_ARCH_PROTOCOL *This, 309 OUT BOOLEAN *State 310 ) 311 { 312 CPU_ARCH_PROTOCOL_PRIVATE *Private; 313 314 if (State == NULL) { 315 return EFI_INVALID_PARAMETER; 316 } 317 318 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); 319 *State = Private->InterruptState; 320 return EFI_SUCCESS; 321 } 322 323 EFI_STATUS 324 EFIAPI 325 EmuInit ( 326 IN EFI_CPU_ARCH_PROTOCOL *This, 327 IN EFI_CPU_INIT_TYPE InitType 328 ) 329 { 330 CPU_ARCH_PROTOCOL_PRIVATE *Private; 331 332 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); 333 return EFI_UNSUPPORTED; 334 } 335 336 EFI_STATUS 337 EFIAPI 338 EmuRegisterInterruptHandler ( 339 IN EFI_CPU_ARCH_PROTOCOL *This, 340 IN EFI_EXCEPTION_TYPE InterruptType, 341 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler 342 ) 343 { 344 CPU_ARCH_PROTOCOL_PRIVATE *Private; 345 346 // 347 // Do parameter checking for EFI spec conformance 348 // 349 if (InterruptType < 0 || InterruptType > 0xff) { 350 return EFI_UNSUPPORTED; 351 } 352 // 353 // Do nothing for Emu emulation 354 // 355 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); 356 return EFI_UNSUPPORTED; 357 } 358 359 EFI_STATUS 360 EFIAPI 361 EmuGetTimerValue ( 362 IN EFI_CPU_ARCH_PROTOCOL *This, 363 IN UINT32 TimerIndex, 364 OUT UINT64 *TimerValue, 365 OUT UINT64 *TimerPeriod OPTIONAL 366 ) 367 { 368 if (TimerValue == NULL) { 369 return EFI_INVALID_PARAMETER; 370 } 371 372 if (TimerIndex != 0) { 373 return EFI_INVALID_PARAMETER; 374 } 375 376 *TimerValue = gEmuThunk->QueryPerformanceCounter (); 377 378 if (TimerPeriod != NULL) { 379 *TimerPeriod = mTimerPeriod; 380 } 381 382 return EFI_SUCCESS; 383 } 384 385 386 EFI_STATUS 387 EFIAPI 388 EmuSetMemoryAttributes ( 389 IN EFI_CPU_ARCH_PROTOCOL *This, 390 IN EFI_PHYSICAL_ADDRESS BaseAddress, 391 IN UINT64 Length, 392 IN UINT64 Attributes 393 ) 394 { 395 CPU_ARCH_PROTOCOL_PRIVATE *Private; 396 397 // 398 // Check for invalid parameter for Spec conformance 399 // 400 if (Length == 0) { 401 return EFI_INVALID_PARAMETER; 402 } 403 404 // 405 // Do nothing for Nt32 emulation 406 // 407 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); 408 return EFI_UNSUPPORTED; 409 } 410 411 412 413 414 /** 415 Callback function for idle events. 416 417 @param Event Event whose notification function is being invoked. 418 @param Context The pointer to the notification function's context, 419 which is implementation-dependent. 420 421 **/ 422 VOID 423 EFIAPI 424 IdleLoopEventCallback ( 425 IN EFI_EVENT Event, 426 IN VOID *Context 427 ) 428 { 429 gEmuThunk->CpuSleep (); 430 } 431 432 433 EFI_STATUS 434 EFIAPI 435 InitializeCpu ( 436 IN EFI_HANDLE ImageHandle, 437 IN EFI_SYSTEM_TABLE *SystemTable 438 ) 439 { 440 EFI_STATUS Status; 441 UINT64 Frequency; 442 EFI_EVENT IdleLoopEvent; 443 UINTN MaxCpu; 444 445 // 446 // Retrieve the frequency of the performance counter in Hz. 447 // 448 Frequency = gEmuThunk->QueryPerformanceFrequency (); 449 450 // 451 // Convert frequency in Hz to a clock period in femtoseconds. 452 // 453 mTimerPeriod = DivU64x64Remainder (1000000000000000ULL, Frequency, NULL); 454 455 CpuMpServicesInit (&MaxCpu); 456 457 CpuUpdateSmbios (MaxCpu); 458 459 460 Status = gBS->CreateEventEx ( 461 EVT_NOTIFY_SIGNAL, 462 TPL_NOTIFY, 463 IdleLoopEventCallback, 464 NULL, 465 &gIdleLoopEventGuid, 466 &IdleLoopEvent 467 ); 468 ASSERT_EFI_ERROR (Status); 469 470 471 Status = gBS->InstallMultipleProtocolInterfaces ( 472 &mCpuTemplate.Handle, 473 &gEfiCpuArchProtocolGuid, &mCpuTemplate.Cpu, 474 &gEfiCpuIo2ProtocolGuid, &mCpuTemplate.CpuIo, 475 NULL 476 ); 477 ASSERT_EFI_ERROR (Status); 478 479 return Status; 480 } 481