]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EdkNt32Pkg/Dxe/WinNtThunk/Cpu/Cpu.c
Remove all blanks lines to avoid build errors.
[mirror_edk2.git] / EdkNt32Pkg / Dxe / WinNtThunk / Cpu / Cpu.c
... / ...
CommitLineData
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#include "CpuDriver.h"\r
26\r
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 Private = AllocatePool (sizeof (CPU_ARCH_PROTOCOL_PRIVATE));\r
421 ASSERT (Private != NULL);\r
422\r
423 Private->Signature = CPU_ARCH_PROT_PRIVATE_SIGNATURE;\r
424 Private->Cpu.FlushDataCache = WinNtFlushCpuDataCache;\r
425 Private->Cpu.EnableInterrupt = WinNtEnableInterrupt;\r
426 Private->Cpu.DisableInterrupt = WinNtDisableInterrupt;\r
427 Private->Cpu.GetInterruptState = WinNtGetInterruptState;\r
428 Private->Cpu.Init = WinNtInit;\r
429 Private->Cpu.RegisterInterruptHandler = WinNtRegisterInterruptHandler;\r
430 Private->Cpu.GetTimerValue = WinNtGetTimerValue;\r
431 Private->Cpu.SetMemoryAttributes = WinNtSetMemoryAttributes;\r
432\r
433 Private->Cpu.NumberOfTimers = 0;\r
434 Private->Cpu.DmaBufferAlignment = 4;\r
435\r
436 Private->InterruptState = TRUE;\r
437\r
438 Private->CpuIo.Mem.Read = CpuMemoryServiceRead;\r
439 Private->CpuIo.Mem.Write = CpuMemoryServiceWrite;\r
440 Private->CpuIo.Io.Read = CpuIoServiceRead;\r
441 Private->CpuIo.Io.Write = CpuIoServiceWrite;\r
442\r
443\r
444 Private->Handle = NULL;\r
445 Status = gBS->InstallMultipleProtocolInterfaces (\r
446 &Private->Handle,\r
447 &gEfiCpuArchProtocolGuid, &Private->Cpu,\r
448 &gEfiCpuIoProtocolGuid, &Private->CpuIo,\r
449 NULL\r
450 );\r
451 ASSERT_EFI_ERROR (Status);\r
452\r
453 //\r
454 // Install notify function to store processor data to HII database and data hub.\r
455 //\r
456 Status = gBS->CreateEvent (\r
457 EVT_NOTIFY_SIGNAL,\r
458 TPL_CALLBACK,\r
459 WinNtIoProtocolNotifyFunction,\r
460 ImageHandle,\r
461 &Event\r
462 );\r
463 ASSERT (!EFI_ERROR (Status));\r
464\r
465 Status = gBS->RegisterProtocolNotify (\r
466 &gEfiWinNtIoProtocolGuid,\r
467 Event,\r
468 &Registration\r
469 );\r
470 ASSERT (!EFI_ERROR (Status));\r
471\r
472 //\r
473 // Should be at EFI_D_INFO, but lets us now things are running\r
474 //\r
475 DEBUG ((EFI_D_ERROR, "CPU Architectural Protocol Loaded\n"));\r
476\r
477\r
478\r
479 return Status;\r
480}\r
481\r
482UINTN\r
483Atoi (\r
484 CHAR16 *String\r
485 )\r
486/*++\r
487\r
488Routine Description:\r
489 Convert a unicode string to a UINTN\r
490\r
491Arguments:\r
492 String - Unicode string.\r
493\r
494Returns:\r
495 UINTN of the number represented by String.\r
496\r
497--*/\r
498{\r
499 UINTN Number;\r
500 CHAR16 *Str;\r
501\r
502 //\r
503 // skip preceeding white space\r
504 //\r
505 Str = String;\r
506 while ((*Str) && (*Str == ' ' || *Str == '"')) {\r
507 Str++;\r
508 }\r
509 //\r
510 // Convert ot a Number\r
511 //\r
512 Number = 0;\r
513 while (*Str != '\0') {\r
514 if ((*Str >= '0') && (*Str <= '9')) {\r
515 Number = (Number * 10) +*Str - '0';\r
516 } else {\r
517 break;\r
518 }\r
519\r
520 Str++;\r
521 }\r
522\r
523 return Number;\r
524}\r
525\r
526VOID\r
527EFIAPI\r
528WinNtIoProtocolNotifyFunction (\r
529 IN EFI_EVENT Event,\r
530 IN VOID *Context\r
531 )\r
532/*++\r
533\r
534Routine Description:\r
535 This function will log processor version and frequency data to data hub.\r
536\r
537Arguments:\r
538 Event - Event whose notification function is being invoked.\r
539 Context - Pointer to the notification function's context.\r
540\r
541Returns:\r
542 None.\r
543\r
544--*/\r
545{\r
546 EFI_STATUS Status;\r
547 EFI_CPU_DATA_RECORD_BUFFER RecordBuffer;\r
548 EFI_DATA_RECORD_HEADER *Record;\r
549 EFI_SUBCLASS_TYPE1_HEADER *DataHeader;\r
550 UINT32 HeaderSize;\r
551 UINT32 TotalSize;\r
552 UINTN HandleCount;\r
553 UINTN HandleIndex;\r
554 UINT64 MonotonicCount;\r
555 BOOLEAN RecordFound;\r
556 EFI_HANDLE *HandleBuffer;\r
557 EFI_WIN_NT_IO_PROTOCOL *WinNtIo;\r
558 EFI_DATA_HUB_PROTOCOL *DataHub;\r
559 EFI_HII_PROTOCOL *Hii;\r
560 EFI_HII_HANDLE StringHandle;\r
561 EFI_HII_PACKAGES *PackageList;\r
562 STRING_REF Token;\r
563\r
564 DataHub = NULL;\r
565 Token = 0;\r
566 MonotonicCount = 0;\r
567 RecordFound = FALSE;\r
568\r
569 //\r
570 // Retrieve the list of all handles from the handle database\r
571 //\r
572 Status = gBS->LocateHandleBuffer (\r
573 AllHandles,\r
574 &gEfiWinNtIoProtocolGuid,\r
575 NULL,\r
576 &HandleCount,\r
577 &HandleBuffer\r
578 );\r
579 if (EFI_ERROR (Status)) {\r
580 return ;\r
581 }\r
582 //\r
583 // Locate HII protocol\r
584 //\r
585 Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, &Hii);\r
586 if (EFI_ERROR (Status)) {\r
587 return ;\r
588 }\r
589 //\r
590 // Locate DataHub protocol.\r
591 //\r
592 Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, &DataHub);\r
593 if (EFI_ERROR (Status)) {\r
594 return ;\r
595 }\r
596 //\r
597 // Initialize data record header\r
598 //\r
599 mCpuDataRecordHeader.Instance = 1;\r
600 HeaderSize = sizeof (EFI_SUBCLASS_TYPE1_HEADER);\r
601\r
602 RecordBuffer.Raw = AllocatePool (HeaderSize + EFI_CPU_DATA_MAXIMUM_LENGTH);\r
603 if (RecordBuffer.Raw == NULL) {\r
604 return ;\r
605 }\r
606\r
607 CopyMem (RecordBuffer.Raw, &mCpuDataRecordHeader, HeaderSize);\r
608\r
609 //\r
610 // Search the Handle array to find the CPU model and speed information\r
611 //\r
612 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
613 Status = gBS->OpenProtocol (\r
614 HandleBuffer[HandleIndex],\r
615 &gEfiWinNtIoProtocolGuid,\r
616 &WinNtIo,\r
617 Context,\r
618 NULL,\r
619 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
620 );\r
621 if (EFI_ERROR (Status)) {\r
622 continue;\r
623 }\r
624\r
625 if ((WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) &&\r
626 CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtCPUModelGuid)\r
627 ) {\r
628 //\r
629 // Check if this record has been stored in data hub\r
630 //\r
631 do {\r
632 Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record);\r
633 if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {\r
634 DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);\r
635 if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) &&\r
636 (DataHeader->RecordType == ProcessorVersionRecordType)\r
637 ) {\r
638 RecordFound = TRUE;\r
639 }\r
640 }\r
641 } while (MonotonicCount != 0);\r
642\r
643 if (RecordFound) {\r
644 RecordFound = FALSE;\r
645 continue;\r
646 }\r
647 //\r
648 // Initialize strings to HII database\r
649 //\r
650 PackageList = PreparePackages (1, &gEfiProcessorProducerGuid, CpuStrings);\r
651\r
652 Status = Hii->NewPack (Hii, PackageList, &StringHandle);\r
653 ASSERT (!EFI_ERROR (Status));\r
654\r
655 FreePool (PackageList);\r
656\r
657 //\r
658 // Store processor version data record to data hub\r
659 //\r
660 Status = Hii->NewString (Hii, NULL, StringHandle, &Token, WinNtIo->EnvString);\r
661 ASSERT (!EFI_ERROR (Status));\r
662\r
663 RecordBuffer.DataRecord->DataRecordHeader.RecordType = ProcessorVersionRecordType;\r
664 RecordBuffer.DataRecord->VariableRecord.ProcessorVersion = Token;\r
665 TotalSize = HeaderSize + sizeof (EFI_PROCESSOR_VERSION_DATA);\r
666\r
667 Status = DataHub->LogData (\r
668 DataHub,\r
669 &gEfiProcessorSubClassGuid,\r
670 &gEfiProcessorProducerGuid,\r
671 EFI_DATA_RECORD_CLASS_DATA,\r
672 RecordBuffer.Raw,\r
673 TotalSize\r
674 );\r
675 }\r
676\r
677 if ((WinNtIo->WinNtThunk->Signature == EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE) &&\r
678 CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtCPUSpeedGuid)\r
679 ) {\r
680 //\r
681 // Check if this record has been stored in data hub\r
682 //\r
683 do {\r
684 Status = DataHub->GetNextRecord (DataHub, &MonotonicCount, NULL, &Record);\r
685 if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {\r
686 DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *) (Record + 1);\r
687 if (CompareGuid (&Record->DataRecordGuid, &gEfiProcessorSubClassGuid) &&\r
688 (DataHeader->RecordType == ProcessorCoreFrequencyRecordType)\r
689 ) {\r
690 RecordFound = TRUE;\r
691 }\r
692 }\r
693 } while (MonotonicCount != 0);\r
694\r
695 if (RecordFound) {\r
696 RecordFound = FALSE;\r
697 continue;\r
698 }\r
699 //\r
700 // Store CPU frequency data record to data hub\r
701 //\r
702 RecordBuffer.DataRecord->DataRecordHeader.RecordType = ProcessorCoreFrequencyRecordType;\r
703 RecordBuffer.DataRecord->VariableRecord.ProcessorCoreFrequency.Value = (UINT16) Atoi (WinNtIo->EnvString);\r
704 RecordBuffer.DataRecord->VariableRecord.ProcessorCoreFrequency.Exponent = 6;\r
705 TotalSize = HeaderSize + sizeof (EFI_PROCESSOR_CORE_FREQUENCY_DATA);\r
706\r
707 Status = DataHub->LogData (\r
708 DataHub,\r
709 &gEfiProcessorSubClassGuid,\r
710 &gEfiProcessorProducerGuid,\r
711 EFI_DATA_RECORD_CLASS_DATA,\r
712 RecordBuffer.Raw,\r
713 TotalSize\r
714 );\r
715\r
716 FreePool (RecordBuffer.Raw);\r
717 }\r
718\r
719 gBS->CloseProtocol (\r
720 HandleBuffer[HandleIndex],\r
721 &gEfiWinNtIoProtocolGuid,\r
722 Context,\r
723 NULL\r
724 );\r
725 }\r
726}\r