• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**@file
2 
3 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   Cpu.c
15 
16 Abstract:
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 
28 UINT64  mTimerPeriod;
29 
30 CPU_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 //
62 EFI_STATUS
63 EFIAPI
WinNtFlushCpuDataCache(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_PHYSICAL_ADDRESS Start,IN UINT64 Length,IN EFI_CPU_FLUSH_TYPE FlushType)64 WinNtFlushCpuDataCache (
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 
72 Routine 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 
78 Arguments:
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 
85 Returns:
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 
109 EFI_STATUS
110 EFIAPI
WinNtEnableInterrupt(IN EFI_CPU_ARCH_PROTOCOL * This)111 WinNtEnableInterrupt (
112   IN EFI_CPU_ARCH_PROTOCOL  *This
113   )
114 /*++
115 
116 Routine 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 
123 Arguments:
124 
125   Pointer to CPU Architectural Protocol interface
126 
127 Returns:
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 
143 EFI_STATUS
144 EFIAPI
WinNtDisableInterrupt(IN EFI_CPU_ARCH_PROTOCOL * This)145 WinNtDisableInterrupt (
146   IN EFI_CPU_ARCH_PROTOCOL  *This
147   )
148 /*++
149 
150 Routine 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 
157 Arguments:
158 
159   Pointer to CPU Architectural Protocol interface
160 
161 Returns:
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 
177 EFI_STATUS
178 EFIAPI
WinNtGetInterruptState(IN EFI_CPU_ARCH_PROTOCOL * This,OUT BOOLEAN * State)179 WinNtGetInterruptState (
180   IN EFI_CPU_ARCH_PROTOCOL  *This,
181   OUT BOOLEAN               *State
182   )
183 /*++
184 
185 Routine 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 
192 Arguments:
193 
194   Pointer to CPU Architectural Protocol interface
195 
196 Returns:
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 
218 EFI_STATUS
219 EFIAPI
WinNtInit(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_CPU_INIT_TYPE InitType)220 WinNtInit (
221   IN EFI_CPU_ARCH_PROTOCOL  *This,
222   IN EFI_CPU_INIT_TYPE      InitType
223   )
224 /*++
225 
226 Routine Description:
227 
228   This routine would support generation of a CPU INIT.  At
229   present, this code does not provide emulation.
230 
231 Arguments:
232 
233   Pointer to CPU Architectural Protocol interface
234   INIT Type
235 
236 Returns:
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 
249 EFI_STATUS
250 EFIAPI
WinNtRegisterInterruptHandler(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_EXCEPTION_TYPE InterruptType,IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler)251 WinNtRegisterInterruptHandler (
252   IN EFI_CPU_ARCH_PROTOCOL      *This,
253   IN EFI_EXCEPTION_TYPE         InterruptType,
254   IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
255   )
256 /*++
257 
258 Routine Description:
259 
260   This routine would support registration of an interrupt handler.  At
261   present, this code does not provide emulation.
262 
263 Arguments:
264 
265   Pointer to CPU Architectural Protocol interface
266   Pointer to interrupt handlers
267   Interrupt type
268 
269 Returns:
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 
293 EFI_STATUS
294 EFIAPI
WinNtGetTimerValue(IN EFI_CPU_ARCH_PROTOCOL * This,IN UINT32 TimerIndex,OUT UINT64 * TimerValue,OUT UINT64 * TimerPeriod OPTIONAL)295 WinNtGetTimerValue (
296   IN  EFI_CPU_ARCH_PROTOCOL *This,
297   IN  UINT32                TimerIndex,
298   OUT UINT64                *TimerValue,
299   OUT UINT64                *TimerPeriod OPTIONAL
300   )
301 /*++
302 
303 Routine Description:
304 
305   This routine would support querying of an on-CPU timer.  At present,
306   this code does not provide timer emulation.
307 
308 Arguments:
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 
315 Returns:
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 
340 EFI_STATUS
341 EFIAPI
WinNtSetMemoryAttributes(IN EFI_CPU_ARCH_PROTOCOL * This,IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes)342 WinNtSetMemoryAttributes (
343   IN EFI_CPU_ARCH_PROTOCOL  *This,
344   IN EFI_PHYSICAL_ADDRESS   BaseAddress,
345   IN UINT64                 Length,
346   IN UINT64                 Attributes
347   )
348 /*++
349 
350 Routine Description:
351 
352   This routine would support querying of an on-CPU timer.  At present,
353   this code does not provide timer emulation.
354 
355 Arguments:
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 
362 Returns:
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 **/
396 VOID
LogSmbiosData(IN EFI_SMBIOS_PROTOCOL * Smbios,IN UINT8 * Buffer)397 LogSmbiosData (
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 
416 VOID
CpuUpdateSmbios(VOID)417 CpuUpdateSmbios (
418   VOID
419   )
420 /*++
421 
422 Routine Description:
423   This function will log processor version and frequency data to Smbios.
424 
425 Arguments:
426   Event        - Event whose notification function is being invoked.
427   Context      - Pointer to the notification function's context.
428 
429 Returns:
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 
502 EFI_STATUS
503 EFIAPI
InitializeCpu(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)504 InitializeCpu (
505   IN EFI_HANDLE        ImageHandle,
506   IN EFI_SYSTEM_TABLE  *SystemTable
507   )
508 /*++
509 
510 Routine Description:
511 
512   Initialize the state information for the CPU Architectural Protocol
513 
514 Arguments:
515 
516   ImageHandle of the loaded driver
517   Pointer to the System Table
518 
519 Returns:
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