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"
27 #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100
32 IN EFI_HANDLE ImageHandle
,
33 IN EFI_SYSTEM_TABLE
*SystemTable
38 WinNtIoProtocolNotifyFunction (
44 EFI_CPU_DATA_RECORD
*DataRecord
;
46 } EFI_CPU_DATA_RECORD_BUFFER
;
48 EFI_SUBCLASS_TYPE1_HEADER mCpuDataRecordHeader
= {
49 EFI_PROCESSOR_SUBCLASS_VERSION
, // Version
50 sizeof (EFI_SUBCLASS_TYPE1_HEADER
), // Header Size
51 0, // Instance, Initialize later
52 EFI_SUBCLASS_INSTANCE_NON_APPLICABLE
, // SubInstance
53 0 // RecordType, Initialize later
57 // Service routines for the driver
62 WinNtFlushCpuDataCache (
63 IN EFI_CPU_ARCH_PROTOCOL
*This
,
64 IN EFI_PHYSICAL_ADDRESS Start
,
66 IN EFI_CPU_FLUSH_TYPE FlushType
72 This routine would provide support for flushing the CPU data cache.
73 In the case of NT emulation environment, this flushing is not necessary and
74 is thus not implemented.
78 Pointer to CPU Architectural Protocol interface
79 Start adddress in memory to flush
80 Length of memory to flush
89 // TODO: This - add argument and description to function comment
90 // TODO: FlushType - add argument and description to function comment
91 // TODO: EFI_UNSUPPORTED - add return value to function comment
93 if (FlushType
== EfiCpuFlushTypeWriteBackInvalidate
) {
95 // Only WB flush is supported. We actually need do nothing on NT emulator
96 // environment. Classify this to follow EFI spec
101 // Other flush types are not supported by NT emulator
103 return EFI_UNSUPPORTED
;
109 WinNtEnableInterrupt (
110 IN EFI_CPU_ARCH_PROTOCOL
*This
116 This routine provides support for emulation of the interrupt enable of the
117 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
118 Architectural Protocol observes in order to defer behaviour while in its
119 emulated interrupt, or timer tick.
123 Pointer to CPU Architectural Protocol interface
131 // TODO: This - add argument and description to function comment
133 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
135 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
136 Private
->InterruptState
= TRUE
;
143 WinNtDisableInterrupt (
144 IN EFI_CPU_ARCH_PROTOCOL
*This
150 This routine provides support for emulation of the interrupt disable of the
151 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
152 Architectural Protocol observes in order to defer behaviour while in its
153 emulated interrupt, or timer tick.
157 Pointer to CPU Architectural Protocol interface
165 // TODO: This - add argument and description to function comment
167 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
169 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
170 Private
->InterruptState
= FALSE
;
177 WinNtGetInterruptState (
178 IN EFI_CPU_ARCH_PROTOCOL
*This
,
185 This routine provides support for emulation of the interrupt disable of the
186 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
187 Architectural Protocol observes in order to defer behaviour while in its
188 emulated interrupt, or timer tick.
192 Pointer to CPU Architectural Protocol interface
200 // TODO: This - add argument and description to function comment
201 // TODO: State - add argument and description to function comment
202 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
204 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
207 return EFI_INVALID_PARAMETER
;
210 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
211 *State
= Private
->InterruptState
;
219 IN EFI_CPU_ARCH_PROTOCOL
*This
,
220 IN EFI_CPU_INIT_TYPE InitType
226 This routine would support generation of a CPU INIT. At
227 present, this code does not provide emulation.
231 Pointer to CPU Architectural Protocol interface
237 EFI_UNSUPPORTED - not yet implemented
240 // TODO: This - add argument and description to function comment
241 // TODO: InitType - add argument and description to function comment
243 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
245 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
246 return EFI_UNSUPPORTED
;
252 WinNtRegisterInterruptHandler (
253 IN EFI_CPU_ARCH_PROTOCOL
*This
,
254 IN EFI_EXCEPTION_TYPE InterruptType
,
255 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
261 This routine would support registration of an interrupt handler. At
262 present, this code does not provide emulation.
266 Pointer to CPU Architectural Protocol interface
267 Pointer to interrupt handlers
273 EFI_UNSUPPORTED - not yet implemented
276 // TODO: This - add argument and description to function comment
277 // TODO: InterruptType - add argument and description to function comment
278 // TODO: InterruptHandler - add argument and description to function comment
280 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
283 // Do parameter checking for EFI spec conformance
285 if (InterruptType
< 0 || InterruptType
> 0xff) {
286 return EFI_UNSUPPORTED
;
289 // Do nothing for Nt32 emulation
291 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
292 return EFI_UNSUPPORTED
;
299 IN EFI_CPU_ARCH_PROTOCOL
*This
,
300 IN UINT32 TimerIndex
,
301 OUT UINT64
*TimerValue
,
302 OUT UINT64
*TimerPeriod OPTIONAL
308 This routine would support querying of an on-CPU timer. At present,
309 this code does not provide timer emulation.
313 This - Pointer to CPU Architectural Protocol interface
314 TimerIndex - Index of given CPU timer
315 TimerValue - Output of the timer
316 TimerPeriod - Output of the timer period
320 EFI_UNSUPPORTED - not yet implemented
321 EFI_INVALID_PARAMETER - TimeValue is NULL
325 if (TimerValue
== NULL
) {
326 return EFI_INVALID_PARAMETER
;
330 // No timer supported
332 return EFI_UNSUPPORTED
;
338 WinNtSetMemoryAttributes (
339 IN EFI_CPU_ARCH_PROTOCOL
*This
,
340 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
348 This routine would support querying of an on-CPU timer. At present,
349 this code does not provide timer emulation.
353 Pointer to CPU Architectural Protocol interface
354 Start address of memory region
355 The size in bytes of the memory region
356 The bit mask of attributes to set for the memory region
361 EFI_UNSUPPORTED - not yet implemented
364 // TODO: This - add argument and description to function comment
365 // TODO: BaseAddress - add argument and description to function comment
366 // TODO: Length - add argument and description to function comment
367 // TODO: Attributes - add argument and description to function comment
368 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
370 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
373 // Check for invalid parameter for Spec conformance
376 return EFI_INVALID_PARAMETER
;
380 // Do nothing for Nt32 emulation
382 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
383 return EFI_UNSUPPORTED
;
390 IN EFI_HANDLE ImageHandle
,
391 IN EFI_SYSTEM_TABLE
*SystemTable
397 Initialize the state information for the CPU Architectural Protocol
401 ImageHandle of the loaded driver
402 Pointer to the System Table
408 EFI_SUCCESS - protocol instance can be published
409 EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure
410 EFI_DEVICE_ERROR - cannot create the thread
413 // TODO: SystemTable - add argument and description to function comment
417 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
420 Status
= gBS
->AllocatePool (
422 sizeof (CPU_ARCH_PROTOCOL_PRIVATE
),
425 ASSERT_EFI_ERROR (Status
);
427 Private
->Signature
= CPU_ARCH_PROT_PRIVATE_SIGNATURE
;
428 Private
->Cpu
.FlushDataCache
= WinNtFlushCpuDataCache
;
429 Private
->Cpu
.EnableInterrupt
= WinNtEnableInterrupt
;
430 Private
->Cpu
.DisableInterrupt
= WinNtDisableInterrupt
;
431 Private
->Cpu
.GetInterruptState
= WinNtGetInterruptState
;
432 Private
->Cpu
.Init
= WinNtInit
;
433 Private
->Cpu
.RegisterInterruptHandler
= WinNtRegisterInterruptHandler
;
434 Private
->Cpu
.GetTimerValue
= WinNtGetTimerValue
;
435 Private
->Cpu
.SetMemoryAttributes
= WinNtSetMemoryAttributes
;
437 Private
->Cpu
.NumberOfTimers
= 0;
438 Private
->Cpu
.DmaBufferAlignment
= 4;
440 Private
->InterruptState
= TRUE
;
442 Private
->CpuIo
.Mem
.Read
= CpuMemoryServiceRead
;
443 Private
->CpuIo
.Mem
.Write
= CpuMemoryServiceWrite
;
444 Private
->CpuIo
.Io
.Read
= CpuIoServiceRead
;
445 Private
->CpuIo
.Io
.Write
= CpuIoServiceWrite
;
448 Private
->Handle
= NULL
;
449 Status
= gBS
->InstallMultipleProtocolInterfaces (
451 &gEfiCpuArchProtocolGuid
, &Private
->Cpu
,
452 &gEfiCpuIoProtocolGuid
, &Private
->CpuIo
,
455 ASSERT_EFI_ERROR (Status
);
458 // Install notify function to store processor data to HII database and data hub.
460 Status
= gBS
->CreateEvent (
461 EFI_EVENT_NOTIFY_SIGNAL
,
463 WinNtIoProtocolNotifyFunction
,
467 ASSERT (!EFI_ERROR (Status
));
469 Status
= gBS
->RegisterProtocolNotify (
470 &gEfiWinNtIoProtocolGuid
,
474 ASSERT (!EFI_ERROR (Status
));
477 // Should be at EFI_D_INFO, but lets us now things are running
479 DEBUG ((EFI_D_ERROR
, "CPU Architectural Protocol Loaded\n"));
493 Convert a unicode string to a UINTN
496 String - Unicode string.
499 UINTN of the number represented by String.
507 // skip preceeding white space
510 while ((*Str
) && (*Str
== ' ' || *Str
== '"')) {
514 // Convert ot a Number
517 while (*Str
!= '\0') {
518 if ((*Str
>= '0') && (*Str
<= '9')) {
519 Number
= (Number
* 10) +*Str
- '0';
532 WinNtIoProtocolNotifyFunction (
539 This function will log processor version and frequency data to data hub.
542 Event - Event whose notification function is being invoked.
543 Context - Pointer to the notification function's context.
551 EFI_CPU_DATA_RECORD_BUFFER RecordBuffer
;
552 EFI_DATA_RECORD_HEADER
*Record
;
553 EFI_SUBCLASS_TYPE1_HEADER
*DataHeader
;
558 UINT64 MonotonicCount
;
560 EFI_HANDLE
*HandleBuffer
;
561 EFI_WIN_NT_IO_PROTOCOL
*WinNtIo
;
562 EFI_DATA_HUB_PROTOCOL
*DataHub
;
563 EFI_HII_PROTOCOL
*Hii
;
564 EFI_HII_HANDLE StringHandle
;
565 EFI_HII_PACKAGES
*PackageList
;
574 // Retrieve the list of all handles from the handle database
576 Status
= gBS
->LocateHandleBuffer (
578 &gEfiWinNtIoProtocolGuid
,
583 if (EFI_ERROR (Status
)) {
587 // Locate HII protocol
589 Status
= gBS
->LocateProtocol (&gEfiHiiProtocolGuid
, NULL
, &Hii
);
590 if (EFI_ERROR (Status
)) {
594 // Locate DataHub protocol.
596 Status
= gBS
->LocateProtocol (&gEfiDataHubProtocolGuid
, NULL
, &DataHub
);
597 if (EFI_ERROR (Status
)) {
601 // Initialize data record header
603 mCpuDataRecordHeader
.Instance
= 1;
604 HeaderSize
= sizeof (EFI_SUBCLASS_TYPE1_HEADER
);
606 RecordBuffer
.Raw
= AllocatePool (HeaderSize
+ EFI_CPU_DATA_MAXIMUM_LENGTH
);
607 if (RecordBuffer
.Raw
== NULL
) {
611 CopyMem (RecordBuffer
.Raw
, &mCpuDataRecordHeader
, HeaderSize
);
614 // Search the Handle array to find the CPU model and speed information
616 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
617 Status
= gBS
->OpenProtocol (
618 HandleBuffer
[HandleIndex
],
619 &gEfiWinNtIoProtocolGuid
,
623 EFI_OPEN_PROTOCOL_GET_PROTOCOL
625 if (EFI_ERROR (Status
)) {
629 if ((WinNtIo
->WinNtThunk
->Signature
== EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE
) &&
630 CompareGuid (WinNtIo
->TypeGuid
, &gEfiWinNtCPUModelGuid
)
633 // Check if this record has been stored in data hub
636 Status
= DataHub
->GetNextRecord (DataHub
, &MonotonicCount
, NULL
, &Record
);
637 if (Record
->DataRecordClass
== EFI_DATA_RECORD_CLASS_DATA
) {
638 DataHeader
= (EFI_SUBCLASS_TYPE1_HEADER
*) (Record
+ 1);
639 if (CompareGuid (&Record
->DataRecordGuid
, &gEfiProcessorSubClassGuid
) &&
640 (DataHeader
->RecordType
== ProcessorVersionRecordType
)
645 } while (MonotonicCount
!= 0);
652 // Initialize strings to HII database
654 PackageList
= PreparePackages (1, &gEfiProcessorProducerGuid
, CpuStrings
);
656 Status
= Hii
->NewPack (Hii
, PackageList
, &StringHandle
);
657 ASSERT (!EFI_ERROR (Status
));
659 gBS
->FreePool (PackageList
);
662 // Store processor version data record to data hub
664 Status
= Hii
->NewString (Hii
, NULL
, StringHandle
, &Token
, WinNtIo
->EnvString
);
665 ASSERT (!EFI_ERROR (Status
));
667 RecordBuffer
.DataRecord
->DataRecordHeader
.RecordType
= ProcessorVersionRecordType
;
668 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorVersion
= Token
;
669 TotalSize
= HeaderSize
+ sizeof (EFI_PROCESSOR_VERSION_DATA
);
671 Status
= DataHub
->LogData (
673 &gEfiProcessorSubClassGuid
,
674 &gEfiProcessorProducerGuid
,
675 EFI_DATA_RECORD_CLASS_DATA
,
681 if ((WinNtIo
->WinNtThunk
->Signature
== EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE
) &&
682 CompareGuid (WinNtIo
->TypeGuid
, &gEfiWinNtCPUSpeedGuid
)
685 // Check if this record has been stored in data hub
688 Status
= DataHub
->GetNextRecord (DataHub
, &MonotonicCount
, NULL
, &Record
);
689 if (Record
->DataRecordClass
== EFI_DATA_RECORD_CLASS_DATA
) {
690 DataHeader
= (EFI_SUBCLASS_TYPE1_HEADER
*) (Record
+ 1);
691 if (CompareGuid (&Record
->DataRecordGuid
, &gEfiProcessorSubClassGuid
) &&
692 (DataHeader
->RecordType
== ProcessorCoreFrequencyRecordType
)
697 } while (MonotonicCount
!= 0);
704 // Store CPU frequency data record to data hub
706 RecordBuffer
.DataRecord
->DataRecordHeader
.RecordType
= ProcessorCoreFrequencyRecordType
;
707 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorCoreFrequency
.Value
= (UINT16
) Atoi (WinNtIo
->EnvString
);
708 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorCoreFrequency
.Exponent
= 6;
709 TotalSize
= HeaderSize
+ sizeof (EFI_PROCESSOR_CORE_FREQUENCY_DATA
);
711 Status
= DataHub
->LogData (
713 &gEfiProcessorSubClassGuid
,
714 &gEfiProcessorProducerGuid
,
715 EFI_DATA_RECORD_CLASS_DATA
,
720 gBS
->FreePool (RecordBuffer
.Raw
);
724 HandleBuffer
[HandleIndex
],
725 &gEfiWinNtIoProtocolGuid
,