Add dependency for RealAsm file build rules and Use the module name in place of macro...
[mirror_edk2.git] / EdkNt32Pkg / Dxe / WinNtThunk / Cpu / Cpu.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 Cpu.c\r
15\r
16Abstract:\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
878ddf1f 27#define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100\r
28\r
29EFI_STATUS\r
30EFIAPI\r
31InitializeCpu (\r
32 IN EFI_HANDLE ImageHandle,\r
33 IN EFI_SYSTEM_TABLE *SystemTable\r
34 );\r
35\r
36VOID\r
37EFIAPI\r
38WinNtIoProtocolNotifyFunction (\r
39 IN EFI_EVENT Event,\r
40 IN VOID *Context\r
41 );\r
42\r
43typedef union {\r
44 EFI_CPU_DATA_RECORD *DataRecord;\r
45 UINT8 *Raw;\r
46} EFI_CPU_DATA_RECORD_BUFFER;\r
47\r
48EFI_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
59STATIC\r
60EFI_STATUS\r
61EFIAPI\r
62WinNtFlushCpuDataCache (\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
70Routine 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
76Arguments:\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
83Returns:\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
106STATIC\r
107EFI_STATUS\r
108EFIAPI\r
109WinNtEnableInterrupt (\r
110 IN EFI_CPU_ARCH_PROTOCOL *This\r
111 )\r
112/*++\r
113\r
114Routine 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
121Arguments:\r
122\r
123 Pointer to CPU Architectural Protocol interface\r
124\r
125Returns:\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
140STATIC\r
141EFI_STATUS\r
142EFIAPI\r
143WinNtDisableInterrupt (\r
144 IN EFI_CPU_ARCH_PROTOCOL *This\r
145 )\r
146/*++\r
147\r
148Routine 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
155Arguments:\r
156\r
157 Pointer to CPU Architectural Protocol interface\r
158\r
159Returns:\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
174STATIC\r
175EFI_STATUS\r
176EFIAPI\r
177WinNtGetInterruptState (\r
178 IN EFI_CPU_ARCH_PROTOCOL *This,\r
179 OUT BOOLEAN *State\r
180 )\r
181/*++\r
182\r
183Routine 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
190Arguments:\r
191\r
192 Pointer to CPU Architectural Protocol interface\r
193\r
194Returns:\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
215STATIC\r
216EFI_STATUS\r
217EFIAPI\r
218WinNtInit (\r
219 IN EFI_CPU_ARCH_PROTOCOL *This,\r
220 IN EFI_CPU_INIT_TYPE InitType\r
221 )\r
222/*++\r
223\r
224Routine 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
229Arguments:\r
230\r
231 Pointer to CPU Architectural Protocol interface\r
232 INIT Type\r
233\r
234Returns:\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
249STATIC\r
250EFI_STATUS\r
251EFIAPI\r
252WinNtRegisterInterruptHandler (\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
259Routine 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
264Arguments:\r
265\r
266 Pointer to CPU Architectural Protocol interface\r
267 Pointer to interrupt handlers\r
268 Interrupt type\r
269\r
270Returns:\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
295STATIC\r
296EFI_STATUS\r
297EFIAPI\r
298WinNtGetTimerValue (\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
306Routine 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
311Arguments:\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
318Returns:\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
335STATIC\r
336EFI_STATUS\r
337EFIAPI\r
338WinNtSetMemoryAttributes (\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
346Routine 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
351Arguments:\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
358Returns:\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
387EFI_STATUS\r
388EFIAPI\r
389InitializeCpu (\r
390 IN EFI_HANDLE ImageHandle,\r
391 IN EFI_SYSTEM_TABLE *SystemTable\r
392 )\r
393/*++\r
394\r
395Routine Description:\r
396\r
397 Initialize the state information for the CPU Architectural Protocol\r
398\r
399Arguments:\r
400\r
401 ImageHandle of the loaded driver\r
402 Pointer to the System Table\r
403\r
404Returns:\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
486UINTN\r
487Atoi (\r
488 CHAR16 *String\r
489 )\r
490/*++\r
491\r
492Routine Description:\r
493 Convert a unicode string to a UINTN\r
494\r
495Arguments:\r
496 String - Unicode string.\r
497\r
498Returns: \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
530VOID\r
531EFIAPI\r
532WinNtIoProtocolNotifyFunction (\r
533 IN EFI_EVENT Event,\r
534 IN VOID *Context\r
535 )\r
536/*++\r
537\r
538Routine Description:\r
539 This function will log processor version and frequency data to data hub.\r
540\r
541Arguments:\r
542 Event - Event whose notification function is being invoked.\r
543 Context - Pointer to the notification function's context.\r
544\r
545Returns:\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
741fb364 654 PackageList = PreparePackages (1, &gEfiProcessorProducerGuid, CpuStrings);\r
878ddf1f 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