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