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