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   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