3 Copyright (c) 2006 - 2007, 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
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.
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
26 // Include common header file for this module.
28 #include "CommonHeader.h"
30 #include "CpuDriver.h"
32 #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100
37 IN EFI_HANDLE ImageHandle
,
38 IN EFI_SYSTEM_TABLE
*SystemTable
43 WinNtIoProtocolNotifyFunction (
49 EFI_CPU_DATA_RECORD
*DataRecord
;
51 } EFI_CPU_DATA_RECORD_BUFFER
;
53 EFI_SUBCLASS_TYPE1_HEADER mCpuDataRecordHeader
= {
54 EFI_PROCESSOR_SUBCLASS_VERSION
, // Version
55 sizeof (EFI_SUBCLASS_TYPE1_HEADER
), // Header Size
56 0, // Instance, Initialize later
57 EFI_SUBCLASS_INSTANCE_NON_APPLICABLE
, // SubInstance
58 0 // RecordType, Initialize later
62 // Service routines for the driver
67 WinNtFlushCpuDataCache (
68 IN EFI_CPU_ARCH_PROTOCOL
*This
,
69 IN EFI_PHYSICAL_ADDRESS Start
,
71 IN EFI_CPU_FLUSH_TYPE FlushType
77 This routine would provide support for flushing the CPU data cache.
78 In the case of NT emulation environment, this flushing is not necessary and
79 is thus not implemented.
83 Pointer to CPU Architectural Protocol interface
84 Start adddress in memory to flush
85 Length of memory to flush
94 // TODO: This - add argument and description to function comment
95 // TODO: FlushType - add argument and description to function comment
96 // TODO: EFI_UNSUPPORTED - add return value to function comment
98 if (FlushType
== EfiCpuFlushTypeWriteBackInvalidate
) {
100 // Only WB flush is supported. We actually need do nothing on NT emulator
101 // environment. Classify this to follow EFI spec
106 // Other flush types are not supported by NT emulator
108 return EFI_UNSUPPORTED
;
114 WinNtEnableInterrupt (
115 IN EFI_CPU_ARCH_PROTOCOL
*This
121 This routine provides support for emulation of the interrupt enable of the
122 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
123 Architectural Protocol observes in order to defer behaviour while in its
124 emulated interrupt, or timer tick.
128 Pointer to CPU Architectural Protocol interface
136 // TODO: This - add argument and description to function comment
138 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
140 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
141 Private
->InterruptState
= TRUE
;
148 WinNtDisableInterrupt (
149 IN EFI_CPU_ARCH_PROTOCOL
*This
155 This routine provides support for emulation of the interrupt disable of the
156 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
157 Architectural Protocol observes in order to defer behaviour while in its
158 emulated interrupt, or timer tick.
162 Pointer to CPU Architectural Protocol interface
170 // TODO: This - add argument and description to function comment
172 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
174 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
175 Private
->InterruptState
= FALSE
;
182 WinNtGetInterruptState (
183 IN EFI_CPU_ARCH_PROTOCOL
*This
,
190 This routine provides support for emulation of the interrupt disable of the
191 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
192 Architectural Protocol observes in order to defer behaviour while in its
193 emulated interrupt, or timer tick.
197 Pointer to CPU Architectural Protocol interface
205 // TODO: This - add argument and description to function comment
206 // TODO: State - add argument and description to function comment
207 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
209 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
212 return EFI_INVALID_PARAMETER
;
215 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
216 *State
= Private
->InterruptState
;
224 IN EFI_CPU_ARCH_PROTOCOL
*This
,
225 IN EFI_CPU_INIT_TYPE InitType
231 This routine would support generation of a CPU INIT. At
232 present, this code does not provide emulation.
236 Pointer to CPU Architectural Protocol interface
242 EFI_UNSUPPORTED - not yet implemented
245 // TODO: This - add argument and description to function comment
246 // TODO: InitType - add argument and description to function comment
248 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
250 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
251 return EFI_UNSUPPORTED
;
257 WinNtRegisterInterruptHandler (
258 IN EFI_CPU_ARCH_PROTOCOL
*This
,
259 IN EFI_EXCEPTION_TYPE InterruptType
,
260 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
266 This routine would support registration of an interrupt handler. At
267 present, this code does not provide emulation.
271 Pointer to CPU Architectural Protocol interface
272 Pointer to interrupt handlers
278 EFI_UNSUPPORTED - not yet implemented
281 // TODO: This - add argument and description to function comment
282 // TODO: InterruptType - add argument and description to function comment
283 // TODO: InterruptHandler - add argument and description to function comment
285 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
288 // Do parameter checking for EFI spec conformance
290 if (InterruptType
< 0 || InterruptType
> 0xff) {
291 return EFI_UNSUPPORTED
;
294 // Do nothing for Nt32 emulation
296 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
297 return EFI_UNSUPPORTED
;
304 IN EFI_CPU_ARCH_PROTOCOL
*This
,
305 IN UINT32 TimerIndex
,
306 OUT UINT64
*TimerValue
,
307 OUT UINT64
*TimerPeriod OPTIONAL
313 This routine would support querying of an on-CPU timer. At present,
314 this code does not provide timer emulation.
318 This - Pointer to CPU Architectural Protocol interface
319 TimerIndex - Index of given CPU timer
320 TimerValue - Output of the timer
321 TimerPeriod - Output of the timer period
325 EFI_UNSUPPORTED - not yet implemented
326 EFI_INVALID_PARAMETER - TimeValue is NULL
330 if (TimerValue
== NULL
) {
331 return EFI_INVALID_PARAMETER
;
335 // No timer supported
337 return EFI_UNSUPPORTED
;
343 WinNtSetMemoryAttributes (
344 IN EFI_CPU_ARCH_PROTOCOL
*This
,
345 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
353 This routine would support querying of an on-CPU timer. At present,
354 this code does not provide timer emulation.
358 Pointer to CPU Architectural Protocol interface
359 Start address of memory region
360 The size in bytes of the memory region
361 The bit mask of attributes to set for the memory region
366 EFI_UNSUPPORTED - not yet implemented
369 // TODO: This - add argument and description to function comment
370 // TODO: BaseAddress - add argument and description to function comment
371 // TODO: Length - add argument and description to function comment
372 // TODO: Attributes - add argument and description to function comment
373 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
375 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
378 // Check for invalid parameter for Spec conformance
381 return EFI_INVALID_PARAMETER
;
385 // Do nothing for Nt32 emulation
387 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
388 return EFI_UNSUPPORTED
;
395 IN EFI_HANDLE ImageHandle
,
396 IN EFI_SYSTEM_TABLE
*SystemTable
402 Initialize the state information for the CPU Architectural Protocol
406 ImageHandle of the loaded driver
407 Pointer to the System Table
413 EFI_SUCCESS - protocol instance can be published
414 EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure
415 EFI_DEVICE_ERROR - cannot create the thread
418 // TODO: SystemTable - add argument and description to function comment
422 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
425 Private
= AllocatePool (sizeof (CPU_ARCH_PROTOCOL_PRIVATE
));
426 ASSERT (Private
!= NULL
);
428 Private
->Signature
= CPU_ARCH_PROT_PRIVATE_SIGNATURE
;
429 Private
->Cpu
.FlushDataCache
= WinNtFlushCpuDataCache
;
430 Private
->Cpu
.EnableInterrupt
= WinNtEnableInterrupt
;
431 Private
->Cpu
.DisableInterrupt
= WinNtDisableInterrupt
;
432 Private
->Cpu
.GetInterruptState
= WinNtGetInterruptState
;
433 Private
->Cpu
.Init
= WinNtInit
;
434 Private
->Cpu
.RegisterInterruptHandler
= WinNtRegisterInterruptHandler
;
435 Private
->Cpu
.GetTimerValue
= WinNtGetTimerValue
;
436 Private
->Cpu
.SetMemoryAttributes
= WinNtSetMemoryAttributes
;
438 Private
->Cpu
.NumberOfTimers
= 0;
439 Private
->Cpu
.DmaBufferAlignment
= 4;
441 Private
->InterruptState
= TRUE
;
443 Private
->CpuIo
.Mem
.Read
= CpuMemoryServiceRead
;
444 Private
->CpuIo
.Mem
.Write
= CpuMemoryServiceWrite
;
445 Private
->CpuIo
.Io
.Read
= CpuIoServiceRead
;
446 Private
->CpuIo
.Io
.Write
= CpuIoServiceWrite
;
449 Private
->Handle
= NULL
;
450 Status
= gBS
->InstallMultipleProtocolInterfaces (
452 &gEfiCpuArchProtocolGuid
, &Private
->Cpu
,
453 &gEfiCpuIoProtocolGuid
, &Private
->CpuIo
,
456 ASSERT_EFI_ERROR (Status
);
459 // Install notify function to store processor data to HII database and data hub.
461 Status
= gBS
->CreateEvent (
464 WinNtIoProtocolNotifyFunction
,
468 ASSERT (!EFI_ERROR (Status
));
470 Status
= gBS
->RegisterProtocolNotify (
471 &gEfiWinNtIoProtocolGuid
,
475 ASSERT (!EFI_ERROR (Status
));
478 // Should be at EFI_D_INFO, but lets us now things are running
480 DEBUG ((EFI_D_ERROR
, "CPU Architectural Protocol Loaded\n"));
494 Convert a unicode string to a UINTN
497 String - Unicode string.
500 UINTN of the number represented by String.
508 // skip preceeding white space
511 while ((*Str
) && (*Str
== ' ' || *Str
== '"')) {
515 // Convert ot a Number
518 while (*Str
!= '\0') {
519 if ((*Str
>= '0') && (*Str
<= '9')) {
520 Number
= (Number
* 10) +*Str
- '0';
533 WinNtIoProtocolNotifyFunction (
540 This function will log processor version and frequency data to data hub.
543 Event - Event whose notification function is being invoked.
544 Context - Pointer to the notification function's context.
552 EFI_CPU_DATA_RECORD_BUFFER RecordBuffer
;
553 EFI_DATA_RECORD_HEADER
*Record
;
554 EFI_SUBCLASS_TYPE1_HEADER
*DataHeader
;
559 UINT64 MonotonicCount
;
561 EFI_HANDLE
*HandleBuffer
;
562 EFI_WIN_NT_IO_PROTOCOL
*WinNtIo
;
563 EFI_DATA_HUB_PROTOCOL
*DataHub
;
564 EFI_HII_PROTOCOL
*Hii
;
565 EFI_HII_HANDLE StringHandle
;
566 EFI_HII_PACKAGES
*PackageList
;
575 // Retrieve the list of all handles from the handle database
577 Status
= gBS
->LocateHandleBuffer (
579 &gEfiWinNtIoProtocolGuid
,
584 if (EFI_ERROR (Status
)) {
588 // Locate HII protocol
590 Status
= gBS
->LocateProtocol (&gEfiHiiProtocolGuid
, NULL
, &Hii
);
591 if (EFI_ERROR (Status
)) {
595 // Locate DataHub protocol.
597 Status
= gBS
->LocateProtocol (&gEfiDataHubProtocolGuid
, NULL
, &DataHub
);
598 if (EFI_ERROR (Status
)) {
602 // Initialize data record header
604 mCpuDataRecordHeader
.Instance
= 1;
605 HeaderSize
= sizeof (EFI_SUBCLASS_TYPE1_HEADER
);
607 RecordBuffer
.Raw
= AllocatePool (HeaderSize
+ EFI_CPU_DATA_MAXIMUM_LENGTH
);
608 if (RecordBuffer
.Raw
== NULL
) {
612 CopyMem (RecordBuffer
.Raw
, &mCpuDataRecordHeader
, HeaderSize
);
615 // Search the Handle array to find the CPU model and speed information
617 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
618 Status
= gBS
->OpenProtocol (
619 HandleBuffer
[HandleIndex
],
620 &gEfiWinNtIoProtocolGuid
,
624 EFI_OPEN_PROTOCOL_GET_PROTOCOL
626 if (EFI_ERROR (Status
)) {
630 if ((WinNtIo
->WinNtThunk
->Signature
== EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE
) &&
631 CompareGuid (WinNtIo
->TypeGuid
, &gEfiWinNtCPUModelGuid
)
634 // Check if this record has been stored in data hub
637 Status
= DataHub
->GetNextRecord (DataHub
, &MonotonicCount
, NULL
, &Record
);
638 if (Record
->DataRecordClass
== EFI_DATA_RECORD_CLASS_DATA
) {
639 DataHeader
= (EFI_SUBCLASS_TYPE1_HEADER
*) (Record
+ 1);
640 if (CompareGuid (&Record
->DataRecordGuid
, &gEfiProcessorSubClassGuid
) &&
641 (DataHeader
->RecordType
== ProcessorVersionRecordType
)
646 } while (MonotonicCount
!= 0);
653 // Initialize strings to HII database
655 PackageList
= PreparePackages (1, &gEfiProcessorProducerGuid
, CpuStrings
);
657 Status
= Hii
->NewPack (Hii
, PackageList
, &StringHandle
);
658 ASSERT (!EFI_ERROR (Status
));
660 FreePool (PackageList
);
663 // Store processor version data record to data hub
665 Status
= Hii
->NewString (Hii
, NULL
, StringHandle
, &Token
, WinNtIo
->EnvString
);
666 ASSERT (!EFI_ERROR (Status
));
668 RecordBuffer
.DataRecord
->DataRecordHeader
.RecordType
= ProcessorVersionRecordType
;
669 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorVersion
= Token
;
670 TotalSize
= HeaderSize
+ sizeof (EFI_PROCESSOR_VERSION_DATA
);
672 Status
= DataHub
->LogData (
674 &gEfiProcessorSubClassGuid
,
675 &gEfiProcessorProducerGuid
,
676 EFI_DATA_RECORD_CLASS_DATA
,
682 if ((WinNtIo
->WinNtThunk
->Signature
== EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE
) &&
683 CompareGuid (WinNtIo
->TypeGuid
, &gEfiWinNtCPUSpeedGuid
)
686 // Check if this record has been stored in data hub
689 Status
= DataHub
->GetNextRecord (DataHub
, &MonotonicCount
, NULL
, &Record
);
690 if (Record
->DataRecordClass
== EFI_DATA_RECORD_CLASS_DATA
) {
691 DataHeader
= (EFI_SUBCLASS_TYPE1_HEADER
*) (Record
+ 1);
692 if (CompareGuid (&Record
->DataRecordGuid
, &gEfiProcessorSubClassGuid
) &&
693 (DataHeader
->RecordType
== ProcessorCoreFrequencyRecordType
)
698 } while (MonotonicCount
!= 0);
705 // Store CPU frequency data record to data hub
707 RecordBuffer
.DataRecord
->DataRecordHeader
.RecordType
= ProcessorCoreFrequencyRecordType
;
708 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorCoreFrequency
.Value
= (UINT16
) Atoi (WinNtIo
->EnvString
);
709 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorCoreFrequency
.Exponent
= 6;
710 TotalSize
= HeaderSize
+ sizeof (EFI_PROCESSOR_CORE_FREQUENCY_DATA
);
712 Status
= DataHub
->LogData (
714 &gEfiProcessorSubClassGuid
,
715 &gEfiProcessorProducerGuid
,
716 EFI_DATA_RECORD_CLASS_DATA
,
721 FreePool (RecordBuffer
.Raw
);
725 HandleBuffer
[HandleIndex
],
726 &gEfiWinNtIoProtocolGuid
,