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