1/**@file 2 3Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> 4This program and the accompanying materials 5are licensed and made available under the terms and conditions of the BSD License 6which accompanies this distribution. The full text of the license may be found at 7http://opensource.org/licenses/bsd-license.php 8 9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12Module Name: 13 14 Cpu.c 15 16Abstract: 17 18 NT Emulation Architectural Protocol Driver as defined in Tiano. 19 This CPU module abstracts the interrupt subsystem of a platform and 20 the CPU-specific setjump/long pair. Other services are not implemented 21 in this driver. 22 23**/ 24 25 26#include "CpuDriver.h" 27 28UINT64 mTimerPeriod; 29 30CPU_ARCH_PROTOCOL_PRIVATE mCpuTemplate = { 31 CPU_ARCH_PROT_PRIVATE_SIGNATURE, 32 NULL, 33 { 34 WinNtFlushCpuDataCache, 35 WinNtEnableInterrupt, 36 WinNtDisableInterrupt, 37 WinNtGetInterruptState, 38 WinNtInit, 39 WinNtRegisterInterruptHandler, 40 WinNtGetTimerValue, 41 WinNtSetMemoryAttributes, 42 1, 43 4 44 }, 45 { 46 CpuMemoryServiceRead, 47 CpuMemoryServiceWrite, 48 CpuIoServiceRead, 49 CpuIoServiceWrite 50 }, 51 0, 52 TRUE 53}; 54 55#define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100 56 57 58 59// 60// Service routines for the driver 61// 62EFI_STATUS 63EFIAPI 64WinNtFlushCpuDataCache ( 65 IN EFI_CPU_ARCH_PROTOCOL *This, 66 IN EFI_PHYSICAL_ADDRESS Start, 67 IN UINT64 Length, 68 IN EFI_CPU_FLUSH_TYPE FlushType 69 ) 70/*++ 71 72Routine Description: 73 74 This routine would provide support for flushing the CPU data cache. 75 In the case of NT emulation environment, this flushing is not necessary and 76 is thus not implemented. 77 78Arguments: 79 80 Pointer to CPU Architectural Protocol interface 81 Start adddress in memory to flush 82 Length of memory to flush 83 Flush type 84 85Returns: 86 87 Status 88 EFI_SUCCESS 89 90--*/ 91// TODO: This - add argument and description to function comment 92// TODO: FlushType - add argument and description to function comment 93// TODO: EFI_UNSUPPORTED - add return value to function comment 94{ 95 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { 96 // 97 // Only WB flush is supported. We actually need do nothing on NT emulator 98 // environment. Classify this to follow EFI spec 99 // 100 return EFI_SUCCESS; 101 } 102 // 103 // Other flush types are not supported by NT emulator 104 // 105 return EFI_UNSUPPORTED; 106} 107 108 109EFI_STATUS 110EFIAPI 111WinNtEnableInterrupt ( 112 IN EFI_CPU_ARCH_PROTOCOL *This 113 ) 114/*++ 115 116Routine Description: 117 118 This routine provides support for emulation of the interrupt enable of the 119 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer 120 Architectural Protocol observes in order to defer behaviour while in its 121 emulated interrupt, or timer tick. 122 123Arguments: 124 125 Pointer to CPU Architectural Protocol interface 126 127Returns: 128 129 Status 130 EFI_SUCCESS 131 132--*/ 133// TODO: This - add argument and description to function comment 134{ 135 CPU_ARCH_PROTOCOL_PRIVATE *Private; 136 137 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); 138 Private->InterruptState = TRUE; 139 return EFI_SUCCESS; 140} 141 142 143EFI_STATUS 144EFIAPI 145WinNtDisableInterrupt ( 146 IN EFI_CPU_ARCH_PROTOCOL *This 147 ) 148/*++ 149 150Routine Description: 151 152 This routine provides support for emulation of the interrupt disable of the 153 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer 154 Architectural Protocol observes in order to defer behaviour while in its 155 emulated interrupt, or timer tick. 156 157Arguments: 158 159 Pointer to CPU Architectural Protocol interface 160 161Returns: 162 163 Status 164 EFI_SUCCESS 165 166--*/ 167// TODO: This - add argument and description to function comment 168{ 169 CPU_ARCH_PROTOCOL_PRIVATE *Private; 170 171 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); 172 Private->InterruptState = FALSE; 173 return EFI_SUCCESS; 174} 175 176 177EFI_STATUS 178EFIAPI 179WinNtGetInterruptState ( 180 IN EFI_CPU_ARCH_PROTOCOL *This, 181 OUT BOOLEAN *State 182 ) 183/*++ 184 185Routine Description: 186 187 This routine provides support for emulation of the interrupt disable of the 188 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer 189 Architectural Protocol observes in order to defer behaviour while in its 190 emulated interrupt, or timer tick. 191 192Arguments: 193 194 Pointer to CPU Architectural Protocol interface 195 196Returns: 197 198 Status 199 EFI_SUCCESS 200 201--*/ 202// TODO: This - add argument and description to function comment 203// TODO: State - add argument and description to function comment 204// TODO: EFI_INVALID_PARAMETER - add return value to function comment 205{ 206 CPU_ARCH_PROTOCOL_PRIVATE *Private; 207 208 if (State == NULL) { 209 return EFI_INVALID_PARAMETER; 210 } 211 212 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); 213 *State = Private->InterruptState; 214 return EFI_SUCCESS; 215} 216 217 218EFI_STATUS 219EFIAPI 220WinNtInit ( 221 IN EFI_CPU_ARCH_PROTOCOL *This, 222 IN EFI_CPU_INIT_TYPE InitType 223 ) 224/*++ 225 226Routine Description: 227 228 This routine would support generation of a CPU INIT. At 229 present, this code does not provide emulation. 230 231Arguments: 232 233 Pointer to CPU Architectural Protocol interface 234 INIT Type 235 236Returns: 237 238 Status 239 EFI_UNSUPPORTED - not yet implemented 240 241--*/ 242// TODO: This - add argument and description to function comment 243// TODO: InitType - add argument and description to function comment 244{ 245 return EFI_UNSUPPORTED; 246} 247 248 249EFI_STATUS 250EFIAPI 251WinNtRegisterInterruptHandler ( 252 IN EFI_CPU_ARCH_PROTOCOL *This, 253 IN EFI_EXCEPTION_TYPE InterruptType, 254 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler 255 ) 256/*++ 257 258Routine Description: 259 260 This routine would support registration of an interrupt handler. At 261 present, this code does not provide emulation. 262 263Arguments: 264 265 Pointer to CPU Architectural Protocol interface 266 Pointer to interrupt handlers 267 Interrupt type 268 269Returns: 270 271 Status 272 EFI_UNSUPPORTED - not yet implemented 273 274--*/ 275// TODO: This - add argument and description to function comment 276// TODO: InterruptType - add argument and description to function comment 277// TODO: InterruptHandler - add argument and description to function comment 278{ 279 280 // 281 // Do parameter checking for EFI spec conformance 282 // 283 if (InterruptType < 0 || InterruptType > 0xff) { 284 return EFI_UNSUPPORTED; 285 } 286 // 287 // Do nothing for Nt32 emulation 288 // 289 return EFI_UNSUPPORTED; 290} 291 292 293EFI_STATUS 294EFIAPI 295WinNtGetTimerValue ( 296 IN EFI_CPU_ARCH_PROTOCOL *This, 297 IN UINT32 TimerIndex, 298 OUT UINT64 *TimerValue, 299 OUT UINT64 *TimerPeriod OPTIONAL 300 ) 301/*++ 302 303Routine Description: 304 305 This routine would support querying of an on-CPU timer. At present, 306 this code does not provide timer emulation. 307 308Arguments: 309 310 This - Pointer to CPU Architectural Protocol interface 311 TimerIndex - Index of given CPU timer 312 TimerValue - Output of the timer 313 TimerPeriod - Output of the timer period 314 315Returns: 316 317 EFI_UNSUPPORTED - not yet implemented 318 EFI_INVALID_PARAMETER - TimeValue is NULL 319 320--*/ 321{ 322 if (TimerValue == NULL) { 323 return EFI_INVALID_PARAMETER; 324 } 325 326 if (TimerIndex != 0) { 327 return EFI_INVALID_PARAMETER; 328 } 329 330 gWinNt->QueryPerformanceCounter ((LARGE_INTEGER *)TimerValue); 331 332 if (TimerPeriod != NULL) { 333 *TimerPeriod = mTimerPeriod; 334 } 335 336 return EFI_SUCCESS; 337} 338 339 340EFI_STATUS 341EFIAPI 342WinNtSetMemoryAttributes ( 343 IN EFI_CPU_ARCH_PROTOCOL *This, 344 IN EFI_PHYSICAL_ADDRESS BaseAddress, 345 IN UINT64 Length, 346 IN UINT64 Attributes 347 ) 348/*++ 349 350Routine Description: 351 352 This routine would support querying of an on-CPU timer. At present, 353 this code does not provide timer emulation. 354 355Arguments: 356 357 Pointer to CPU Architectural Protocol interface 358 Start address of memory region 359 The size in bytes of the memory region 360 The bit mask of attributes to set for the memory region 361 362Returns: 363 364 Status 365 EFI_UNSUPPORTED - not yet implemented 366 367--*/ 368// TODO: This - add argument and description to function comment 369// TODO: BaseAddress - add argument and description to function comment 370// TODO: Length - add argument and description to function comment 371// TODO: Attributes - add argument and description to function comment 372// TODO: EFI_INVALID_PARAMETER - add return value to function comment 373{ 374 // 375 // Check for invalid parameter for Spec conformance 376 // 377 if (Length == 0) { 378 return EFI_INVALID_PARAMETER; 379 } 380 381 // 382 // Do nothing for Nt32 emulation 383 // 384 return EFI_UNSUPPORTED; 385} 386 387 388 389/** 390 Logs SMBIOS record. 391 392 @param Smbios Pointer to SMBIOS protocol instance. 393 @param Buffer Pointer to the data buffer. 394 395**/ 396VOID 397LogSmbiosData ( 398 IN EFI_SMBIOS_PROTOCOL *Smbios, 399 IN UINT8 *Buffer 400 ) 401{ 402 EFI_STATUS Status; 403 EFI_SMBIOS_HANDLE SmbiosHandle; 404 405 SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; 406 Status = Smbios->Add ( 407 Smbios, 408 NULL, 409 &SmbiosHandle, 410 (EFI_SMBIOS_TABLE_HEADER*)Buffer 411 ); 412 ASSERT_EFI_ERROR (Status); 413} 414 415 416VOID 417CpuUpdateSmbios ( 418 VOID 419 ) 420/*++ 421 422Routine Description: 423 This function will log processor version and frequency data to Smbios. 424 425Arguments: 426 Event - Event whose notification function is being invoked. 427 Context - Pointer to the notification function's context. 428 429Returns: 430 None. 431 432--*/ 433{ 434 EFI_STATUS Status; 435 UINT32 TotalSize; 436 EFI_SMBIOS_PROTOCOL *Smbios; 437 EFI_HII_HANDLE HiiHandle; 438 STRING_REF Token; 439 UINTN CpuVerStrLen; 440 EFI_STRING CpuVerStr; 441 SMBIOS_TABLE_TYPE4 *SmbiosRecord; 442 CHAR8 *OptionalStrStart; 443 444 // 445 // Locate Smbios protocol. 446 // 447 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios); 448 449 if (EFI_ERROR (Status)) { 450 return; 451 } 452 453 // 454 // Initialize strings to HII database 455 // 456 HiiHandle = HiiAddPackages ( 457 &gEfiCallerIdGuid, 458 NULL, 459 CpuStrings, 460 NULL 461 ); 462 ASSERT (HiiHandle != NULL); 463 464 Token = STRING_TOKEN (STR_PROCESSOR_VERSION); 465 CpuVerStr = HiiGetPackageString(&gEfiCallerIdGuid, Token, NULL); 466 CpuVerStrLen = StrLen(CpuVerStr); 467 ASSERT (CpuVerStrLen <= SMBIOS_STRING_MAX_LENGTH); 468 469 470 TotalSize = (UINT32)(sizeof(SMBIOS_TABLE_TYPE4) + CpuVerStrLen + 1 + 1); 471 SmbiosRecord = AllocatePool(TotalSize); 472 ZeroMem(SmbiosRecord, TotalSize); 473 474 SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION; 475 SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4); 476 // 477 // Make handle chosen by smbios protocol.add automatically. 478 // 479 SmbiosRecord->Hdr.Handle = 0; 480 // 481 // Processor version is the 1st string. 482 // 483 SmbiosRecord->ProcessorVersion = 1; 484 // 485 // Store CPU frequency data record to data hub - It's an emulator so make up a value 486 // 487 SmbiosRecord->CurrentSpeed = 1234; 488 489 OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1); 490 UnicodeStrToAsciiStr(CpuVerStr, OptionalStrStart); 491 492 // 493 // Now we have got the full smbios record, call smbios protocol to add this record. 494 // 495 LogSmbiosData(Smbios, (UINT8 *) SmbiosRecord); 496 FreePool (SmbiosRecord); 497 498} 499 500 501 502EFI_STATUS 503EFIAPI 504InitializeCpu ( 505 IN EFI_HANDLE ImageHandle, 506 IN EFI_SYSTEM_TABLE *SystemTable 507 ) 508/*++ 509 510Routine Description: 511 512 Initialize the state information for the CPU Architectural Protocol 513 514Arguments: 515 516 ImageHandle of the loaded driver 517 Pointer to the System Table 518 519Returns: 520 521 Status 522 523 EFI_SUCCESS - protocol instance can be published 524 EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure 525 EFI_DEVICE_ERROR - cannot create the thread 526 527--*/ 528{ 529 EFI_STATUS Status; 530 UINT64 Frequency; 531 532 // 533 // Retrieve the frequency of the performance counter in Hz. 534 // 535 gWinNt->QueryPerformanceFrequency ((LARGE_INTEGER *)&Frequency); 536 537 // 538 // Convert frequency in Hz to a clock period in femtoseconds. 539 // 540 mTimerPeriod = DivU64x64Remainder (1000000000000000, Frequency, NULL); 541 542 CpuUpdateSmbios (); 543 544 Status = gBS->InstallMultipleProtocolInterfaces ( 545 &mCpuTemplate.Handle, 546 &gEfiCpuArchProtocolGuid, &mCpuTemplate.Cpu, 547 &gEfiCpuIo2ProtocolGuid, &mCpuTemplate.CpuIo, 548 NULL 549 ); 550 ASSERT_EFI_ERROR (Status); 551 552 return Status; 553} 554