/**@file Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: Cpu.c Abstract: NT Emulation Architectural Protocol Driver as defined in Tiano. This CPU module abstracts the interrupt subsystem of a platform and the CPU-specific setjump/long pair. Other services are not implemented in this driver. **/ #include "CpuDriver.h" UINT64 mTimerPeriod; CPU_ARCH_PROTOCOL_PRIVATE mCpuTemplate = { CPU_ARCH_PROT_PRIVATE_SIGNATURE, NULL, { WinNtFlushCpuDataCache, WinNtEnableInterrupt, WinNtDisableInterrupt, WinNtGetInterruptState, WinNtInit, WinNtRegisterInterruptHandler, WinNtGetTimerValue, WinNtSetMemoryAttributes, 1, 4 }, { CpuMemoryServiceRead, CpuMemoryServiceWrite, CpuIoServiceRead, CpuIoServiceWrite }, 0, TRUE }; #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100 // // Service routines for the driver // EFI_STATUS EFIAPI WinNtFlushCpuDataCache ( IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_PHYSICAL_ADDRESS Start, IN UINT64 Length, IN EFI_CPU_FLUSH_TYPE FlushType ) /*++ Routine Description: This routine would provide support for flushing the CPU data cache. In the case of NT emulation environment, this flushing is not necessary and is thus not implemented. Arguments: Pointer to CPU Architectural Protocol interface Start adddress in memory to flush Length of memory to flush Flush type Returns: Status EFI_SUCCESS --*/ // TODO: This - add argument and description to function comment // TODO: FlushType - add argument and description to function comment // TODO: EFI_UNSUPPORTED - add return value to function comment { if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { // // Only WB flush is supported. We actually need do nothing on NT emulator // environment. Classify this to follow EFI spec // return EFI_SUCCESS; } // // Other flush types are not supported by NT emulator // return EFI_UNSUPPORTED; } EFI_STATUS EFIAPI WinNtEnableInterrupt ( IN EFI_CPU_ARCH_PROTOCOL *This ) /*++ Routine Description: This routine provides support for emulation of the interrupt enable of the the system. For our purposes, CPU enable is just a BOOLEAN that the Timer Architectural Protocol observes in order to defer behaviour while in its emulated interrupt, or timer tick. Arguments: Pointer to CPU Architectural Protocol interface Returns: Status EFI_SUCCESS --*/ // TODO: This - add argument and description to function comment { CPU_ARCH_PROTOCOL_PRIVATE *Private; Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); Private->InterruptState = TRUE; return EFI_SUCCESS; } EFI_STATUS EFIAPI WinNtDisableInterrupt ( IN EFI_CPU_ARCH_PROTOCOL *This ) /*++ Routine Description: This routine provides support for emulation of the interrupt disable of the the system. For our purposes, CPU enable is just a BOOLEAN that the Timer Architectural Protocol observes in order to defer behaviour while in its emulated interrupt, or timer tick. Arguments: Pointer to CPU Architectural Protocol interface Returns: Status EFI_SUCCESS --*/ // TODO: This - add argument and description to function comment { CPU_ARCH_PROTOCOL_PRIVATE *Private; Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); Private->InterruptState = FALSE; return EFI_SUCCESS; } EFI_STATUS EFIAPI WinNtGetInterruptState ( IN EFI_CPU_ARCH_PROTOCOL *This, OUT BOOLEAN *State ) /*++ Routine Description: This routine provides support for emulation of the interrupt disable of the the system. For our purposes, CPU enable is just a BOOLEAN that the Timer Architectural Protocol observes in order to defer behaviour while in its emulated interrupt, or timer tick. Arguments: Pointer to CPU Architectural Protocol interface Returns: Status EFI_SUCCESS --*/ // TODO: This - add argument and description to function comment // TODO: State - add argument and description to function comment // TODO: EFI_INVALID_PARAMETER - add return value to function comment { CPU_ARCH_PROTOCOL_PRIVATE *Private; if (State == NULL) { return EFI_INVALID_PARAMETER; } Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This); *State = Private->InterruptState; return EFI_SUCCESS; } EFI_STATUS EFIAPI WinNtInit ( IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_CPU_INIT_TYPE InitType ) /*++ Routine Description: This routine would support generation of a CPU INIT. At present, this code does not provide emulation. Arguments: Pointer to CPU Architectural Protocol interface INIT Type Returns: Status EFI_UNSUPPORTED - not yet implemented --*/ // TODO: This - add argument and description to function comment // TODO: InitType - add argument and description to function comment { return EFI_UNSUPPORTED; } EFI_STATUS EFIAPI WinNtRegisterInterruptHandler ( IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_EXCEPTION_TYPE InterruptType, IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler ) /*++ Routine Description: This routine would support registration of an interrupt handler. At present, this code does not provide emulation. Arguments: Pointer to CPU Architectural Protocol interface Pointer to interrupt handlers Interrupt type Returns: Status EFI_UNSUPPORTED - not yet implemented --*/ // TODO: This - add argument and description to function comment // TODO: InterruptType - add argument and description to function comment // TODO: InterruptHandler - add argument and description to function comment { // // Do parameter checking for EFI spec conformance // if (InterruptType < 0 || InterruptType > 0xff) { return EFI_UNSUPPORTED; } // // Do nothing for Nt32 emulation // return EFI_UNSUPPORTED; } EFI_STATUS EFIAPI WinNtGetTimerValue ( IN EFI_CPU_ARCH_PROTOCOL *This, IN UINT32 TimerIndex, OUT UINT64 *TimerValue, OUT UINT64 *TimerPeriod OPTIONAL ) /*++ Routine Description: This routine would support querying of an on-CPU timer. At present, this code does not provide timer emulation. Arguments: This - Pointer to CPU Architectural Protocol interface TimerIndex - Index of given CPU timer TimerValue - Output of the timer TimerPeriod - Output of the timer period Returns: EFI_UNSUPPORTED - not yet implemented EFI_INVALID_PARAMETER - TimeValue is NULL --*/ { if (TimerValue == NULL) { return EFI_INVALID_PARAMETER; } if (TimerIndex != 0) { return EFI_INVALID_PARAMETER; } gWinNt->QueryPerformanceCounter ((LARGE_INTEGER *)TimerValue); if (TimerPeriod != NULL) { *TimerPeriod = mTimerPeriod; } return EFI_SUCCESS; } EFI_STATUS EFIAPI WinNtSetMemoryAttributes ( IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN UINT64 Attributes ) /*++ Routine Description: This routine would support querying of an on-CPU timer. At present, this code does not provide timer emulation. Arguments: Pointer to CPU Architectural Protocol interface Start address of memory region The size in bytes of the memory region The bit mask of attributes to set for the memory region Returns: Status EFI_UNSUPPORTED - not yet implemented --*/ // TODO: This - add argument and description to function comment // TODO: BaseAddress - add argument and description to function comment // TODO: Length - add argument and description to function comment // TODO: Attributes - add argument and description to function comment // TODO: EFI_INVALID_PARAMETER - add return value to function comment { // // Check for invalid parameter for Spec conformance // if (Length == 0) { return EFI_INVALID_PARAMETER; } // // Do nothing for Nt32 emulation // return EFI_UNSUPPORTED; } /** Logs SMBIOS record. @param Smbios Pointer to SMBIOS protocol instance. @param Buffer Pointer to the data buffer. **/ VOID LogSmbiosData ( IN EFI_SMBIOS_PROTOCOL *Smbios, IN UINT8 *Buffer ) { EFI_STATUS Status; EFI_SMBIOS_HANDLE SmbiosHandle; SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = Smbios->Add ( Smbios, NULL, &SmbiosHandle, (EFI_SMBIOS_TABLE_HEADER*)Buffer ); ASSERT_EFI_ERROR (Status); } VOID CpuUpdateSmbios ( VOID ) /*++ Routine Description: This function will log processor version and frequency data to Smbios. Arguments: Event - Event whose notification function is being invoked. Context - Pointer to the notification function's context. Returns: None. --*/ { EFI_STATUS Status; UINT32 TotalSize; EFI_SMBIOS_PROTOCOL *Smbios; EFI_HII_HANDLE HiiHandle; STRING_REF Token; UINTN CpuVerStrLen; EFI_STRING CpuVerStr; SMBIOS_TABLE_TYPE4 *SmbiosRecord; CHAR8 *OptionalStrStart; // // Locate Smbios protocol. // Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios); if (EFI_ERROR (Status)) { return; } // // Initialize strings to HII database // HiiHandle = HiiAddPackages ( &gEfiCallerIdGuid, NULL, CpuStrings, NULL ); ASSERT (HiiHandle != NULL); Token = STRING_TOKEN (STR_PROCESSOR_VERSION); CpuVerStr = HiiGetPackageString(&gEfiCallerIdGuid, Token, NULL); CpuVerStrLen = StrLen(CpuVerStr); ASSERT (CpuVerStrLen <= SMBIOS_STRING_MAX_LENGTH); TotalSize = (UINT32)(sizeof(SMBIOS_TABLE_TYPE4) + CpuVerStrLen + 1 + 1); SmbiosRecord = AllocatePool(TotalSize); ZeroMem(SmbiosRecord, TotalSize); SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION; SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4); // // Make handle chosen by smbios protocol.add automatically. // SmbiosRecord->Hdr.Handle = 0; // // Processor version is the 1st string. // SmbiosRecord->ProcessorVersion = 1; // // Store CPU frequency data record to data hub - It's an emulator so make up a value // SmbiosRecord->CurrentSpeed = 1234; OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1); UnicodeStrToAsciiStr(CpuVerStr, OptionalStrStart); // // Now we have got the full smbios record, call smbios protocol to add this record. // LogSmbiosData(Smbios, (UINT8 *) SmbiosRecord); FreePool (SmbiosRecord); } EFI_STATUS EFIAPI InitializeCpu ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /*++ Routine Description: Initialize the state information for the CPU Architectural Protocol Arguments: ImageHandle of the loaded driver Pointer to the System Table Returns: Status EFI_SUCCESS - protocol instance can be published EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure EFI_DEVICE_ERROR - cannot create the thread --*/ { EFI_STATUS Status; UINT64 Frequency; // // Retrieve the frequency of the performance counter in Hz. // gWinNt->QueryPerformanceFrequency ((LARGE_INTEGER *)&Frequency); // // Convert frequency in Hz to a clock period in femtoseconds. // mTimerPeriod = DivU64x64Remainder (1000000000000000, Frequency, NULL); CpuUpdateSmbios (); Status = gBS->InstallMultipleProtocolInterfaces ( &mCpuTemplate.Handle, &gEfiCpuArchProtocolGuid, &mCpuTemplate.Cpu, &gEfiCpuIo2ProtocolGuid, &mCpuTemplate.CpuIo, NULL ); ASSERT_EFI_ERROR (Status); return Status; }