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