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
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
25 #include "CpuDriver.h"
28 // This is the VFR compiler generated header file which defines the
29 // string identifiers.
31 #include STRING_DEFINES_FILE
33 #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100
38 IN EFI_HANDLE ImageHandle
,
39 IN EFI_SYSTEM_TABLE
*SystemTable
44 WinNtIoProtocolNotifyFunction (
50 EFI_CPU_DATA_RECORD
*DataRecord
;
52 } EFI_CPU_DATA_RECORD_BUFFER
;
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
63 // Service routines for the driver
68 WinNtFlushCpuDataCache (
69 IN EFI_CPU_ARCH_PROTOCOL
*This
,
70 IN EFI_PHYSICAL_ADDRESS Start
,
72 IN EFI_CPU_FLUSH_TYPE FlushType
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.
84 Pointer to CPU Architectural Protocol interface
85 Start adddress in memory to flush
86 Length of memory to flush
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
99 if (FlushType
== EfiCpuFlushTypeWriteBackInvalidate
) {
101 // Only WB flush is supported. We actually need do nothing on NT emulator
102 // environment. Classify this to follow EFI spec
107 // Other flush types are not supported by NT emulator
109 return EFI_UNSUPPORTED
;
115 WinNtEnableInterrupt (
116 IN EFI_CPU_ARCH_PROTOCOL
*This
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.
129 Pointer to CPU Architectural Protocol interface
137 // TODO: This - add argument and description to function comment
139 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
141 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
142 Private
->InterruptState
= TRUE
;
149 WinNtDisableInterrupt (
150 IN EFI_CPU_ARCH_PROTOCOL
*This
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.
163 Pointer to CPU Architectural Protocol interface
171 // TODO: This - add argument and description to function comment
173 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
175 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
176 Private
->InterruptState
= FALSE
;
183 WinNtGetInterruptState (
184 IN EFI_CPU_ARCH_PROTOCOL
*This
,
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.
198 Pointer to CPU Architectural Protocol interface
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
210 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
213 return EFI_INVALID_PARAMETER
;
216 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
217 *State
= Private
->InterruptState
;
225 IN EFI_CPU_ARCH_PROTOCOL
*This
,
226 IN EFI_CPU_INIT_TYPE InitType
232 This routine would support generation of a CPU INIT. At
233 present, this code does not provide emulation.
237 Pointer to CPU Architectural Protocol interface
243 EFI_UNSUPPORTED - not yet implemented
246 // TODO: This - add argument and description to function comment
247 // TODO: InitType - add argument and description to function comment
249 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
251 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
252 return EFI_UNSUPPORTED
;
258 WinNtRegisterInterruptHandler (
259 IN EFI_CPU_ARCH_PROTOCOL
*This
,
260 IN EFI_EXCEPTION_TYPE InterruptType
,
261 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
267 This routine would support registration of an interrupt handler. At
268 present, this code does not provide emulation.
272 Pointer to CPU Architectural Protocol interface
273 Pointer to interrupt handlers
279 EFI_UNSUPPORTED - not yet implemented
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
286 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
289 // Do parameter checking for EFI spec conformance
291 if (InterruptType
< 0 || InterruptType
> 0xff) {
292 return EFI_UNSUPPORTED
;
295 // Do nothing for Nt32 emulation
297 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
298 return EFI_UNSUPPORTED
;
305 IN EFI_CPU_ARCH_PROTOCOL
*This
,
306 IN UINT32 TimerIndex
,
307 OUT UINT64
*TimerValue
,
308 OUT UINT64
*TimerPeriod OPTIONAL
314 This routine would support querying of an on-CPU timer. At present,
315 this code does not provide timer emulation.
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
326 EFI_UNSUPPORTED - not yet implemented
327 EFI_INVALID_PARAMETER - TimeValue is NULL
331 if (TimerValue
== NULL
) {
332 return EFI_INVALID_PARAMETER
;
336 // No timer supported
338 return EFI_UNSUPPORTED
;
344 WinNtSetMemoryAttributes (
345 IN EFI_CPU_ARCH_PROTOCOL
*This
,
346 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
354 This routine would support querying of an on-CPU timer. At present,
355 this code does not provide timer emulation.
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
367 EFI_UNSUPPORTED - not yet implemented
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
376 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
379 // Check for invalid parameter for Spec conformance
382 return EFI_INVALID_PARAMETER
;
386 // Do nothing for Nt32 emulation
388 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
389 return EFI_UNSUPPORTED
;
396 IN EFI_HANDLE ImageHandle
,
397 IN EFI_SYSTEM_TABLE
*SystemTable
403 Initialize the state information for the CPU Architectural Protocol
407 ImageHandle of the loaded driver
408 Pointer to the System Table
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
419 // TODO: SystemTable - add argument and description to function comment
423 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
426 Status
= gBS
->AllocatePool (
428 sizeof (CPU_ARCH_PROTOCOL_PRIVATE
),
431 ASSERT_EFI_ERROR (Status
);
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
;
443 Private
->Cpu
.NumberOfTimers
= 0;
444 Private
->Cpu
.DmaBufferAlignment
= 4;
446 Private
->InterruptState
= TRUE
;
448 Private
->CpuIo
.Mem
.Read
= CpuMemoryServiceRead
;
449 Private
->CpuIo
.Mem
.Write
= CpuMemoryServiceWrite
;
450 Private
->CpuIo
.Io
.Read
= CpuIoServiceRead
;
451 Private
->CpuIo
.Io
.Write
= CpuIoServiceWrite
;
454 Private
->Handle
= NULL
;
455 Status
= gBS
->InstallMultipleProtocolInterfaces (
457 &gEfiCpuArchProtocolGuid
, &Private
->Cpu
,
458 &gEfiCpuIoProtocolGuid
, &Private
->CpuIo
,
461 ASSERT_EFI_ERROR (Status
);
464 // Install notify function to store processor data to HII database and data hub.
466 Status
= gBS
->CreateEvent (
467 EFI_EVENT_NOTIFY_SIGNAL
,
469 WinNtIoProtocolNotifyFunction
,
473 ASSERT (!EFI_ERROR (Status
));
475 Status
= gBS
->RegisterProtocolNotify (
476 &gEfiWinNtIoProtocolGuid
,
480 ASSERT (!EFI_ERROR (Status
));
483 // Should be at EFI_D_INFO, but lets us now things are running
485 DEBUG ((EFI_D_ERROR
, "CPU Architectural Protocol Loaded\n"));
499 Convert a unicode string to a UINTN
502 String - Unicode string.
505 UINTN of the number represented by String.
513 // skip preceeding white space
516 while ((*Str
) && (*Str
== ' ' || *Str
== '"')) {
520 // Convert ot a Number
523 while (*Str
!= '\0') {
524 if ((*Str
>= '0') && (*Str
<= '9')) {
525 Number
= (Number
* 10) +*Str
- '0';
538 WinNtIoProtocolNotifyFunction (
545 This function will log processor version and frequency data to data hub.
548 Event - Event whose notification function is being invoked.
549 Context - Pointer to the notification function's context.
557 EFI_CPU_DATA_RECORD_BUFFER RecordBuffer
;
558 EFI_DATA_RECORD_HEADER
*Record
;
559 EFI_SUBCLASS_TYPE1_HEADER
*DataHeader
;
564 UINT64 MonotonicCount
;
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
;
580 // Retrieve the list of all handles from the handle database
582 Status
= gBS
->LocateHandleBuffer (
584 &gEfiWinNtIoProtocolGuid
,
589 if (EFI_ERROR (Status
)) {
593 // Locate HII protocol
595 Status
= gBS
->LocateProtocol (&gEfiHiiProtocolGuid
, NULL
, &Hii
);
596 if (EFI_ERROR (Status
)) {
600 // Locate DataHub protocol.
602 Status
= gBS
->LocateProtocol (&gEfiDataHubProtocolGuid
, NULL
, &DataHub
);
603 if (EFI_ERROR (Status
)) {
607 // Initialize data record header
609 mCpuDataRecordHeader
.Instance
= 1;
610 HeaderSize
= sizeof (EFI_SUBCLASS_TYPE1_HEADER
);
612 RecordBuffer
.Raw
= AllocatePool (HeaderSize
+ EFI_CPU_DATA_MAXIMUM_LENGTH
);
613 if (RecordBuffer
.Raw
== NULL
) {
617 CopyMem (RecordBuffer
.Raw
, &mCpuDataRecordHeader
, HeaderSize
);
620 // Search the Handle array to find the CPU model and speed information
622 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
623 Status
= gBS
->OpenProtocol (
624 HandleBuffer
[HandleIndex
],
625 &gEfiWinNtIoProtocolGuid
,
629 EFI_OPEN_PROTOCOL_GET_PROTOCOL
631 if (EFI_ERROR (Status
)) {
635 if ((WinNtIo
->WinNtThunk
->Signature
== EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE
) &&
636 CompareGuid (WinNtIo
->TypeGuid
, &gEfiWinNtCPUModelGuid
)
639 // Check if this record has been stored in data hub
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
)
651 } while (MonotonicCount
!= 0);
658 // Initialize strings to HII database
660 PackageList
= PreparePackages (1, &gEfiProcessorProducerGuid
, STRING_ARRAY_NAME
);
662 Status
= Hii
->NewPack (Hii
, PackageList
, &StringHandle
);
663 ASSERT (!EFI_ERROR (Status
));
665 gBS
->FreePool (PackageList
);
668 // Store processor version data record to data hub
670 Status
= Hii
->NewString (Hii
, NULL
, StringHandle
, &Token
, WinNtIo
->EnvString
);
671 ASSERT (!EFI_ERROR (Status
));
673 RecordBuffer
.DataRecord
->DataRecordHeader
.RecordType
= ProcessorVersionRecordType
;
674 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorVersion
= Token
;
675 TotalSize
= HeaderSize
+ sizeof (EFI_PROCESSOR_VERSION_DATA
);
677 Status
= DataHub
->LogData (
679 &gEfiProcessorSubClassGuid
,
680 &gEfiProcessorProducerGuid
,
681 EFI_DATA_RECORD_CLASS_DATA
,
687 if ((WinNtIo
->WinNtThunk
->Signature
== EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE
) &&
688 CompareGuid (WinNtIo
->TypeGuid
, &gEfiWinNtCPUSpeedGuid
)
691 // Check if this record has been stored in data hub
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
)
703 } while (MonotonicCount
!= 0);
710 // Store CPU frequency data record to data hub
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
);
717 Status
= DataHub
->LogData (
719 &gEfiProcessorSubClassGuid
,
720 &gEfiProcessorProducerGuid
,
721 EFI_DATA_RECORD_CLASS_DATA
,
726 gBS
->FreePool (RecordBuffer
.Raw
);
730 HandleBuffer
[HandleIndex
],
731 &gEfiWinNtIoProtocolGuid
,