Home | History | Annotate | Download | only in CpuRuntimeDxe
      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   return EFI_UNSUPPORTED;
    331 }
    332 
    333 EFI_STATUS
    334 EFIAPI
    335 EmuRegisterInterruptHandler (
    336   IN EFI_CPU_ARCH_PROTOCOL      *This,
    337   IN EFI_EXCEPTION_TYPE         InterruptType,
    338   IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
    339   )
    340 {
    341   //
    342   // Do parameter checking for EFI spec conformance
    343   //
    344   if (InterruptType < 0 || InterruptType > 0xff) {
    345     return EFI_UNSUPPORTED;
    346   }
    347   //
    348   // Do nothing for Emu emulation
    349   //
    350   return EFI_UNSUPPORTED;
    351 }
    352 
    353 EFI_STATUS
    354 EFIAPI
    355 EmuGetTimerValue (
    356   IN  EFI_CPU_ARCH_PROTOCOL *This,
    357   IN  UINT32                TimerIndex,
    358   OUT UINT64                *TimerValue,
    359   OUT UINT64                *TimerPeriod OPTIONAL
    360   )
    361 {
    362   if (TimerValue == NULL) {
    363     return EFI_INVALID_PARAMETER;
    364   }
    365 
    366   if (TimerIndex != 0) {
    367     return EFI_INVALID_PARAMETER;
    368   }
    369 
    370   *TimerValue = gEmuThunk->QueryPerformanceCounter ();
    371 
    372   if (TimerPeriod != NULL) {
    373     *TimerPeriod = mTimerPeriod;
    374   }
    375 
    376   return EFI_SUCCESS;
    377 }
    378 
    379 
    380 EFI_STATUS
    381 EFIAPI
    382 EmuSetMemoryAttributes (
    383   IN EFI_CPU_ARCH_PROTOCOL  *This,
    384   IN EFI_PHYSICAL_ADDRESS   BaseAddress,
    385   IN UINT64                 Length,
    386   IN UINT64                 Attributes
    387   )
    388 {
    389   //
    390   // Check for invalid parameter for Spec conformance
    391   //
    392   if (Length == 0) {
    393     return EFI_INVALID_PARAMETER;
    394   }
    395 
    396   //
    397   // Do nothing for Nt32 emulation
    398   //
    399   return EFI_UNSUPPORTED;
    400 }
    401 
    402 
    403 
    404 
    405 /**
    406   Callback function for idle events.
    407 
    408   @param  Event                 Event whose notification function is being invoked.
    409   @param  Context               The pointer to the notification function's context,
    410                                 which is implementation-dependent.
    411 
    412 **/
    413 VOID
    414 EFIAPI
    415 IdleLoopEventCallback (
    416   IN EFI_EVENT                Event,
    417   IN VOID                     *Context
    418   )
    419 {
    420   gEmuThunk->CpuSleep ();
    421 }
    422 
    423 
    424 EFI_STATUS
    425 EFIAPI
    426 InitializeCpu (
    427   IN EFI_HANDLE        ImageHandle,
    428   IN EFI_SYSTEM_TABLE  *SystemTable
    429   )
    430 {
    431   EFI_STATUS    Status;
    432   UINT64        Frequency;
    433   EFI_EVENT     IdleLoopEvent;
    434   UINTN         MaxCpu;
    435 
    436   //
    437   // Retrieve the frequency of the performance counter in Hz.
    438   //
    439   Frequency = gEmuThunk->QueryPerformanceFrequency ();
    440 
    441   //
    442   // Convert frequency in Hz to a clock period in femtoseconds.
    443   //
    444   mTimerPeriod = DivU64x64Remainder (1000000000000000ULL, Frequency, NULL);
    445 
    446   CpuMpServicesInit (&MaxCpu);
    447 
    448   CpuUpdateSmbios (MaxCpu);
    449 
    450 
    451   Status = gBS->CreateEventEx (
    452                   EVT_NOTIFY_SIGNAL,
    453                   TPL_NOTIFY,
    454                   IdleLoopEventCallback,
    455                   NULL,
    456                   &gIdleLoopEventGuid,
    457                   &IdleLoopEvent
    458                   );
    459   ASSERT_EFI_ERROR (Status);
    460 
    461 
    462   Status = gBS->InstallMultipleProtocolInterfaces (
    463                   &mCpuTemplate.Handle,
    464                   &gEfiCpuArchProtocolGuid,   &mCpuTemplate.Cpu,
    465                   &gEfiCpuIo2ProtocolGuid,    &mCpuTemplate.CpuIo,
    466                   NULL
    467                   );
    468   ASSERT_EFI_ERROR (Status);
    469 
    470   return Status;
    471 }
    472