Add dependency for RealAsm file build rules and Use the module name in place of macro...
[people/mcb30/edk2.git] / edk2 / EdkNt32Pkg / Dxe / WinNtThunk / Cpu / Cpu.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   Cpu.c\r
15 \r
16 Abstract:\r
17 \r
18   NT Emulation Architectural Protocol Driver as defined in Tiano.\r
19   This CPU module abstracts the interrupt subsystem of a platform and\r
20   the CPU-specific setjump/long pair.  Other services are not implemented\r
21   in this driver.\r
22 \r
23 --*/\r
24 \r
25 #include "CpuDriver.h"\r
26 \r
27 #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100\r
28 \r
29 EFI_STATUS\r
30 EFIAPI\r
31 InitializeCpu (\r
32   IN EFI_HANDLE        ImageHandle,\r
33   IN EFI_SYSTEM_TABLE  *SystemTable\r
34   );\r
35 \r
36 VOID\r
37 EFIAPI\r
38 WinNtIoProtocolNotifyFunction (\r
39   IN EFI_EVENT                Event,\r
40   IN VOID                     *Context\r
41   );\r
42 \r
43 typedef union {\r
44   EFI_CPU_DATA_RECORD *DataRecord;\r
45   UINT8               *Raw;\r
46 } EFI_CPU_DATA_RECORD_BUFFER;\r
47 \r
48 EFI_SUBCLASS_TYPE1_HEADER mCpuDataRecordHeader = {\r
49   EFI_PROCESSOR_SUBCLASS_VERSION,       // Version\r
50   sizeof (EFI_SUBCLASS_TYPE1_HEADER),   // Header Size\r
51   0,                                    // Instance, Initialize later\r
52   EFI_SUBCLASS_INSTANCE_NON_APPLICABLE, // SubInstance\r
53   0                                     // RecordType, Initialize later\r
54 };\r
55 \r
56 //\r
57 // Service routines for the driver\r
58 //\r
59 STATIC\r
60 EFI_STATUS\r
61 EFIAPI\r
62 WinNtFlushCpuDataCache (\r
63   IN EFI_CPU_ARCH_PROTOCOL  *This,\r
64   IN EFI_PHYSICAL_ADDRESS   Start,\r
65   IN UINT64                 Length,\r
66   IN EFI_CPU_FLUSH_TYPE     FlushType\r
67   )\r
68 /*++\r
69 \r
70 Routine Description:\r
71 \r
72   This routine would provide support for flushing the CPU data cache.\r
73   In the case of NT emulation environment, this flushing is not necessary and\r
74   is thus not implemented.\r
75 \r
76 Arguments:\r
77 \r
78   Pointer to CPU Architectural Protocol interface\r
79   Start adddress in memory to flush\r
80   Length of memory to flush\r
81   Flush type\r
82 \r
83 Returns:\r
84 \r
85   Status\r
86     EFI_SUCCESS\r
87 \r
88 --*/\r
89 // TODO:    This - add argument and description to function comment\r
90 // TODO:    FlushType - add argument and description to function comment\r
91 // TODO:    EFI_UNSUPPORTED - add return value to function comment\r
92 {\r
93   if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {\r
94     //\r
95     // Only WB flush is supported. We actually need do nothing on NT emulator\r
96     // environment. Classify this to follow EFI spec\r
97     //\r
98     return EFI_SUCCESS;\r
99   }\r
100   //\r
101   // Other flush types are not supported by NT emulator\r
102   //\r
103   return EFI_UNSUPPORTED;\r
104 }\r
105 \r
106 STATIC\r
107 EFI_STATUS\r
108 EFIAPI\r
109 WinNtEnableInterrupt (\r
110   IN EFI_CPU_ARCH_PROTOCOL  *This\r
111   )\r
112 /*++\r
113 \r
114 Routine Description:\r
115 \r
116   This routine provides support for emulation of the interrupt enable of the\r
117   the system.  For our purposes, CPU enable is just a BOOLEAN that the Timer \r
118   Architectural Protocol observes in order to defer behaviour while in its\r
119   emulated interrupt, or timer tick.\r
120 \r
121 Arguments:\r
122 \r
123   Pointer to CPU Architectural Protocol interface\r
124 \r
125 Returns:\r
126 \r
127   Status\r
128     EFI_SUCCESS\r
129 \r
130 --*/\r
131 // TODO:    This - add argument and description to function comment\r
132 {\r
133   CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
134 \r
135   Private                 = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);\r
136   Private->InterruptState = TRUE;\r
137   return EFI_SUCCESS;\r
138 }\r
139 \r
140 STATIC\r
141 EFI_STATUS\r
142 EFIAPI\r
143 WinNtDisableInterrupt (\r
144   IN EFI_CPU_ARCH_PROTOCOL  *This\r
145   )\r
146 /*++\r
147 \r
148 Routine Description:\r
149 \r
150   This routine provides support for emulation of the interrupt disable of the\r
151   the system.  For our purposes, CPU enable is just a BOOLEAN that the Timer \r
152   Architectural Protocol observes in order to defer behaviour while in its\r
153   emulated interrupt, or timer tick.\r
154 \r
155 Arguments:\r
156 \r
157   Pointer to CPU Architectural Protocol interface\r
158 \r
159 Returns:\r
160 \r
161   Status\r
162     EFI_SUCCESS\r
163 \r
164 --*/\r
165 // TODO:    This - add argument and description to function comment\r
166 {\r
167   CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
168 \r
169   Private                 = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);\r
170   Private->InterruptState = FALSE;\r
171   return EFI_SUCCESS;\r
172 }\r
173 \r
174 STATIC\r
175 EFI_STATUS\r
176 EFIAPI\r
177 WinNtGetInterruptState (\r
178   IN EFI_CPU_ARCH_PROTOCOL  *This,\r
179   OUT BOOLEAN               *State\r
180   )\r
181 /*++\r
182 \r
183 Routine Description:\r
184 \r
185   This routine provides support for emulation of the interrupt disable of the\r
186   the system.  For our purposes, CPU enable is just a BOOLEAN that the Timer \r
187   Architectural Protocol observes in order to defer behaviour while in its\r
188   emulated interrupt, or timer tick.\r
189 \r
190 Arguments:\r
191 \r
192   Pointer to CPU Architectural Protocol interface\r
193 \r
194 Returns:\r
195 \r
196   Status\r
197     EFI_SUCCESS\r
198 \r
199 --*/\r
200 // TODO:    This - add argument and description to function comment\r
201 // TODO:    State - add argument and description to function comment\r
202 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
203 {\r
204   CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
205 \r
206   if (State == NULL) {\r
207     return EFI_INVALID_PARAMETER;\r
208   }\r
209 \r
210   Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);\r
211   *State  = Private->InterruptState;\r
212   return EFI_SUCCESS;\r
213 }\r
214 \r
215 STATIC\r
216 EFI_STATUS\r
217 EFIAPI\r
218 WinNtInit (\r
219   IN EFI_CPU_ARCH_PROTOCOL  *This,\r
220   IN EFI_CPU_INIT_TYPE      InitType\r
221   )\r
222 /*++\r
223 \r
224 Routine Description:\r
225 \r
226   This routine would support generation of a CPU INIT.  At \r
227   present, this code does not provide emulation.  \r
228 \r
229 Arguments:\r
230 \r
231   Pointer to CPU Architectural Protocol interface\r
232   INIT Type\r
233 \r
234 Returns:\r
235 \r
236   Status\r
237     EFI_UNSUPPORTED - not yet implemented\r
238 \r
239 --*/\r
240 // TODO:    This - add argument and description to function comment\r
241 // TODO:    InitType - add argument and description to function comment\r
242 {\r
243   CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
244 \r
245   Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);\r
246   return EFI_UNSUPPORTED;\r
247 }\r
248 \r
249 STATIC\r
250 EFI_STATUS\r
251 EFIAPI\r
252 WinNtRegisterInterruptHandler (\r
253   IN EFI_CPU_ARCH_PROTOCOL      *This,\r
254   IN EFI_EXCEPTION_TYPE         InterruptType,\r
255   IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler\r
256   )\r
257 /*++\r
258 \r
259 Routine Description:\r
260 \r
261   This routine would support registration of an interrupt handler.  At \r
262   present, this code does not provide emulation.  \r
263 \r
264 Arguments:\r
265 \r
266   Pointer to CPU Architectural Protocol interface\r
267   Pointer to interrupt handlers\r
268   Interrupt type\r
269 \r
270 Returns:\r
271 \r
272   Status\r
273     EFI_UNSUPPORTED - not yet implemented\r
274 \r
275 --*/\r
276 // TODO:    This - add argument and description to function comment\r
277 // TODO:    InterruptType - add argument and description to function comment\r
278 // TODO:    InterruptHandler - add argument and description to function comment\r
279 {\r
280   CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
281 \r
282   //\r
283   // Do parameter checking for EFI spec conformance\r
284   //\r
285   if (InterruptType < 0 || InterruptType > 0xff) {\r
286     return EFI_UNSUPPORTED;\r
287   }\r
288   //\r
289   // Do nothing for Nt32 emulation\r
290   //\r
291   Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);\r
292   return EFI_UNSUPPORTED;\r
293 }\r
294 \r
295 STATIC\r
296 EFI_STATUS\r
297 EFIAPI\r
298 WinNtGetTimerValue (\r
299   IN  EFI_CPU_ARCH_PROTOCOL *This,\r
300   IN  UINT32                TimerIndex,\r
301   OUT UINT64                *TimerValue,\r
302   OUT UINT64                *TimerPeriod OPTIONAL\r
303   )\r
304 /*++\r
305 \r
306 Routine Description:\r
307 \r
308   This routine would support querying of an on-CPU timer.  At present, \r
309   this code does not provide timer emulation.  \r
310 \r
311 Arguments:\r
312 \r
313   This        - Pointer to CPU Architectural Protocol interface\r
314   TimerIndex  - Index of given CPU timer\r
315   TimerValue  - Output of the timer\r
316   TimerPeriod - Output of the timer period\r
317 \r
318 Returns:\r
319 \r
320   EFI_UNSUPPORTED       - not yet implemented\r
321   EFI_INVALID_PARAMETER - TimeValue is NULL\r
322 \r
323 --*/\r
324 {\r
325   if (TimerValue == NULL) {\r
326     return EFI_INVALID_PARAMETER;\r
327   }\r
328   \r
329   //\r
330   // No timer supported\r
331   //\r
332   return EFI_UNSUPPORTED;\r
333 }\r
334 \r
335 STATIC\r
336 EFI_STATUS\r
337 EFIAPI\r
338 WinNtSetMemoryAttributes (\r
339   IN EFI_CPU_ARCH_PROTOCOL  *This,\r
340   IN EFI_PHYSICAL_ADDRESS   BaseAddress,\r
341   IN UINT64                 Length,\r
342   IN UINT64                 Attributes\r
343   )\r
344 /*++\r
345 \r
346 Routine Description:\r
347 \r
348   This routine would support querying of an on-CPU timer.  At present, \r
349   this code does not provide timer emulation.  \r
350 \r
351 Arguments:\r
352 \r
353   Pointer to CPU Architectural Protocol interface\r
354   Start address of memory region\r
355   The size in bytes of the memory region\r
356   The bit mask of attributes to set for the memory region\r
357 \r
358 Returns:\r
359 \r
360   Status\r
361     EFI_UNSUPPORTED - not yet implemented\r
362 \r
363 --*/\r
364 // TODO:    This - add argument and description to function comment\r
365 // TODO:    BaseAddress - add argument and description to function comment\r
366 // TODO:    Length - add argument and description to function comment\r
367 // TODO:    Attributes - add argument and description to function comment\r
368 // TODO:    EFI_INVALID_PARAMETER - add return value to function comment\r
369 {\r
370   CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
371 \r
372   //\r
373   // Check for invalid parameter for Spec conformance\r
374   //\r
375   if (Length == 0) {\r
376     return EFI_INVALID_PARAMETER;\r
377   }\r
378 \r
379   //\r
380   // Do nothing for Nt32 emulation\r
381   //\r
382   Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);\r
383   return EFI_UNSUPPORTED;\r
384 }\r
385 \r
386 \r
387 EFI_STATUS\r
388 EFIAPI\r
389 InitializeCpu (\r
390   IN EFI_HANDLE        ImageHandle,\r
391   IN EFI_SYSTEM_TABLE  *SystemTable\r
392   )\r
393 /*++\r
394 \r
395 Routine Description:\r
396 \r
397   Initialize the state information for the CPU Architectural Protocol\r
398 \r
399 Arguments:\r
400 \r
401   ImageHandle of the loaded driver\r
402   Pointer to the System Table\r
403 \r
404 Returns:\r
405 \r
406   Status\r
407 \r
408   EFI_SUCCESS           - protocol instance can be published \r
409   EFI_OUT_OF_RESOURCES  - cannot allocate protocol data structure\r
410   EFI_DEVICE_ERROR      - cannot create the thread\r
411 \r
412 --*/\r
413 // TODO:    SystemTable - add argument and description to function comment\r
414 {\r
415   EFI_STATUS                Status;\r
416   EFI_EVENT                 Event;\r
417   CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
418   VOID                      *Registration;\r
419 \r
420   Status = gBS->AllocatePool (\r
421                   EfiBootServicesData,\r
422                   sizeof (CPU_ARCH_PROTOCOL_PRIVATE),\r
423                   &Private\r
424                   );\r
425   ASSERT_EFI_ERROR (Status);\r
426 \r
427   Private->Signature                    = CPU_ARCH_PROT_PRIVATE_SIGNATURE;\r
428   Private->Cpu.FlushDataCache           = WinNtFlushCpuDataCache;\r
429   Private->Cpu.EnableInterrupt          = WinNtEnableInterrupt;\r
430   Private->Cpu.DisableInterrupt         = WinNtDisableInterrupt;\r
431   Private->Cpu.GetInterruptState        = WinNtGetInterruptState;\r
432   Private->Cpu.Init                     = WinNtInit;\r
433   Private->Cpu.RegisterInterruptHandler = WinNtRegisterInterruptHandler;\r
434   Private->Cpu.GetTimerValue            = WinNtGetTimerValue;\r
435   Private->Cpu.SetMemoryAttributes      = WinNtSetMemoryAttributes;\r
436 \r
437   Private->Cpu.NumberOfTimers           = 0;\r
438   Private->Cpu.DmaBufferAlignment       = 4;\r
439 \r
440   Private->InterruptState               = TRUE;\r
441 \r
442   Private->CpuIo.Mem.Read   = CpuMemoryServiceRead;\r
443   Private->CpuIo.Mem.Write  = CpuMemoryServiceWrite;\r
444   Private->CpuIo.Io.Read    = CpuIoServiceRead;\r
445   Private->CpuIo.Io.Write   = CpuIoServiceWrite;\r
446 \r
447 \r
448   Private->Handle                       = NULL;\r
449   Status = gBS->InstallMultipleProtocolInterfaces (\r
450                   &Private->Handle,\r
451                   &gEfiCpuArchProtocolGuid,   &Private->Cpu,\r
452                   &gEfiCpuIoProtocolGuid,     &Private->CpuIo,\r
453                   NULL\r
454                   );\r
455   ASSERT_EFI_ERROR (Status);\r
456 \r
457   //\r
458   // Install notify function to store processor data to HII database and data hub.\r
459   //\r
460   Status = gBS->CreateEvent (\r
461                   EFI_EVENT_NOTIFY_SIGNAL,\r
462                   EFI_TPL_CALLBACK,\r
463                   WinNtIoProtocolNotifyFunction,\r
464                   ImageHandle,\r
465                   &Event\r
466                   );\r
467   ASSERT (!EFI_ERROR (Status));\r
468 \r
469   Status = gBS->RegisterProtocolNotify (\r
470                   &gEfiWinNtIoProtocolGuid,\r
471                   Event,\r
472                   &Registration\r
473                   );\r
474   ASSERT (!EFI_ERROR (Status));\r
475 \r
476   //\r
477   // Should be at EFI_D_INFO, but lets us now things are running\r
478   //\r
479   DEBUG ((EFI_D_ERROR, "CPU Architectural Protocol Loaded\n"));\r
480 \r
481 \r
482   \r
483   return Status;\r
484 }\r
485 \r
486 UINTN\r
487 Atoi (\r
488   CHAR16  *String\r
489   )\r
490 /*++\r
491 \r
492 Routine Description:\r
493   Convert a unicode string to a UINTN\r
494 \r
495 Arguments:\r
496   String - Unicode string.\r
497 \r
498 Returns: \r
499   UINTN of the number represented by String.  \r
500 \r
501 --*/\r
502 {\r
503   UINTN   Number;\r
504   CHAR16  *Str;\r
505 \r
506   //\r
507   // skip preceeding white space\r
508   //\r
509   Str = String;\r
510   while ((*Str) && (*Str == ' ' || *Str == '"')) {\r
511     Str++;\r
512   }\r
513   //\r
514   // Convert ot a Number\r
515   //\r
516   Number = 0;\r
517   while (*Str != '\0') {\r
518     if ((*Str >= '0') && (*Str <= '9')) {\r
519       Number = (Number * 10) +*Str - '0';\r
520     } else {\r
521       break;\r
522     }\r
523 \r
524     Str++;\r
525   }\r
526 \r
527   return Number;\r
528 }\r
529 \r
530 VOID\r
531 EFIAPI\r
532 WinNtIoProtocolNotifyFunction (\r
533   IN EFI_EVENT                Event,\r
534   IN VOID                     *Context\r
535   )\r
536 /*++\r
537 \r
538 Routine Description:\r
539   This function will log processor version and frequency data to data hub.\r
540 \r
541 Arguments:\r
542   Event        - Event whose notification function is being invoked.\r
543   Context      - Pointer to the notification function's context.\r
544 \r
545 Returns:\r
546   None.\r
547 \r
548 --*/\r
549 {\r
550   EFI_STATUS                  Status;\r
551   EFI_CPU_DATA_RECORD_BUFFER  RecordBuffer;\r
552   EFI_DATA_RECORD_HEADER      *Record;\r
553   EFI_SUBCLASS_TYPE1_HEADER   *DataHeader;\r
554   UINT32                      HeaderSize;\r
555   UINT32                      TotalSize;\r
556   UINTN                       HandleCount;\r
557   UINTN                       HandleIndex;\r
558   UINT64                      MonotonicCount;\r
559   BOOLEAN                     RecordFound;\r
560   EFI_HANDLE                  *HandleBuffer;\r
561   EFI_WIN_NT_IO_PROTOCOL      *WinNtIo;\r
562   EFI_DATA_HUB_PROTOCOL       *DataHub;\r
563   EFI_HII_PROTOCOL            *Hii;\r
564   EFI_HII_HANDLE              StringHandle;\r
565   EFI_HII_PACKAGES            *PackageList;\r
566   STRING_REF                  Token;\r
567 \r
568   DataHub         = NULL;\r
569   Token           = 0;\r
570   MonotonicCount  = 0;\r
571   RecordFound     = FALSE;\r
572 \r
573   //\r
574   // Retrieve the list of all handles from the handle database\r
575   //\r
576   Status = gBS->LocateHandleBuffer (\r
577                   AllHandles,\r
578                   &gEfiWinNtIoProtocolGuid,\r
579                   NULL,\r
580                   &HandleCount,\r
581                   &HandleBuffer\r
582                   );\r
583   if (EFI_ERROR (Status)) {\r
584     return ;\r
585   }\r
586   //\r
587   // Locate HII protocol\r
588   //\r
589   Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, &Hii);\r
590   if (EFI_ERROR (Status)) {\r
591     return ;\r
592   }\r
593   //\r
594   // Locate DataHub protocol.\r
595   //\r
596   Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, &DataHub);\r
597   if (EFI_ERROR (Status)) {\r
598     return ;\r
599   }\r
600   //\r
601   // Initialize data record header\r
602   //\r
603   mCpuDataRecordHeader.Instance = 1;\r
604   HeaderSize                    = sizeof (EFI_SUBCLASS_TYPE1_HEADER);\r
605 \r
606   RecordBuffer.Raw              = AllocatePool (HeaderSize + EFI_CPU_DATA_MAXIMUM_LENGTH);\r
607   if (RecordBuffer.Raw == NULL) {\r
608     return ;\r
609   }\r
610 \r
611   CopyMem (RecordBuffer.Raw, &mCpuDataRecordHeader, HeaderSize);\r
612 \r
613   //\r
614   // Search the Handle array to find the CPU model and speed information\r
615   //\r
616   for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
617     Status = gBS->OpenProtocol (\r
618                     HandleBuffer[HandleIndex],\r
619                     &gEfiWinNtIoProtocolGuid,\r
620                     &WinNtIo,\r
621                     Context,\r
622                     NULL,\r
623                     EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
624                     );\r
625     if (EFI_ERROR (Status)) {\r
626       continue;\r
627     }\r
628 \r
629     if ((WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) &&\r
630         CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtCPUModelGuid)\r
631           ) {\r
632       //\r
633       // Check if this record has been stored in data hub\r
634       //\r
635       do {\r
636         Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record);\r
637         if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {\r
638           DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);\r
639           if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) &&\r
640               (DataHeader->RecordType == ProcessorVersionRecordType)\r
641               ) {\r
642             RecordFound = TRUE;\r
643           }\r
644         }\r
645       } while (MonotonicCount != 0);\r
646 \r
647       if (RecordFound) {\r
648         RecordFound = FALSE;\r
649         continue;\r
650       }\r
651       //\r
652       // Initialize strings to HII database\r
653       //\r
654       PackageList = PreparePackages (1, &gEfiProcessorProducerGuid, CpuStrings);\r
655 \r
656       Status      = Hii->NewPack (Hii, PackageList, &StringHandle);\r
657       ASSERT (!EFI_ERROR (Status));\r
658 \r
659       gBS->FreePool (PackageList);\r
660 \r
661       //\r
662       // Store processor version data record to data hub\r
663       //\r
664       Status = Hii->NewString (Hii, NULL, StringHandle, &Token, WinNtIo->EnvString);\r
665       ASSERT (!EFI_ERROR (Status));\r
666 \r
667       RecordBuffer.DataRecord->DataRecordHeader.RecordType      = ProcessorVersionRecordType;\r
668       RecordBuffer.DataRecord->VariableRecord.ProcessorVersion  = Token;\r
669       TotalSize = HeaderSize + sizeof (EFI_PROCESSOR_VERSION_DATA);\r
670 \r
671       Status = DataHub->LogData (\r
672                           DataHub,\r
673                           &gEfiProcessorSubClassGuid,\r
674                           &gEfiProcessorProducerGuid,\r
675                           EFI_DATA_RECORD_CLASS_DATA,\r
676                           RecordBuffer.Raw,\r
677                           TotalSize\r
678                           );\r
679     }\r
680 \r
681     if ((WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) &&\r
682         CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtCPUSpeedGuid)\r
683           ) {\r
684       //\r
685       // Check if this record has been stored in data hub\r
686       //\r
687       do {\r
688         Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record);\r
689         if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {\r
690           DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);\r
691           if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) &&\r
692               (DataHeader->RecordType == ProcessorCoreFrequencyRecordType)\r
693               ) {\r
694             RecordFound = TRUE;\r
695           }\r
696         }\r
697       } while (MonotonicCount != 0);\r
698 \r
699       if (RecordFound) {\r
700         RecordFound = FALSE;\r
701         continue;\r
702       }\r
703       //\r
704       // Store CPU frequency data record to data hub\r
705       //\r
706       RecordBuffer.DataRecord->DataRecordHeader.RecordType                    = ProcessorCoreFrequencyRecordType;\r
707       RecordBuffer.DataRecord->VariableRecord.ProcessorCoreFrequency.Value    = (UINT16) Atoi (WinNtIo->EnvString);\r
708       RecordBuffer.DataRecord->VariableRecord.ProcessorCoreFrequency.Exponent = 6;\r
709       TotalSize = HeaderSize + sizeof (EFI_PROCESSOR_CORE_FREQUENCY_DATA);\r
710 \r
711       Status = DataHub->LogData (\r
712                           DataHub,\r
713                           &gEfiProcessorSubClassGuid,\r
714                           &gEfiProcessorProducerGuid,\r
715                           EFI_DATA_RECORD_CLASS_DATA,\r
716                           RecordBuffer.Raw,\r
717                           TotalSize\r
718                           );\r
719 \r
720       gBS->FreePool (RecordBuffer.Raw);\r
721     }\r
722 \r
723     gBS->CloseProtocol (\r
724           HandleBuffer[HandleIndex],\r
725           &gEfiWinNtIoProtocolGuid,\r
726           Context,\r
727           NULL\r
728           );\r
729   }\r
730 }\r