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 "CpuDriver.h"
28 #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100
33 IN EFI_HANDLE ImageHandle
,
34 IN EFI_SYSTEM_TABLE
*SystemTable
39 WinNtIoProtocolNotifyFunction (
45 EFI_CPU_DATA_RECORD
*DataRecord
;
47 } EFI_CPU_DATA_RECORD_BUFFER
;
49 EFI_SUBCLASS_TYPE1_HEADER mCpuDataRecordHeader
= {
50 EFI_PROCESSOR_SUBCLASS_VERSION
, // Version
51 sizeof (EFI_SUBCLASS_TYPE1_HEADER
), // Header Size
52 0, // Instance, Initialize later
53 EFI_SUBCLASS_INSTANCE_NON_APPLICABLE
, // SubInstance
54 0 // RecordType, Initialize later
58 // Service routines for the driver
63 WinNtFlushCpuDataCache (
64 IN EFI_CPU_ARCH_PROTOCOL
*This
,
65 IN EFI_PHYSICAL_ADDRESS Start
,
67 IN EFI_CPU_FLUSH_TYPE FlushType
73 This routine would provide support for flushing the CPU data cache.
74 In the case of NT emulation environment, this flushing is not necessary and
75 is thus not implemented.
79 Pointer to CPU Architectural Protocol interface
80 Start adddress in memory to flush
81 Length of memory to flush
90 // TODO: This - add argument and description to function comment
91 // TODO: FlushType - add argument and description to function comment
92 // TODO: EFI_UNSUPPORTED - add return value to function comment
94 if (FlushType
== EfiCpuFlushTypeWriteBackInvalidate
) {
96 // Only WB flush is supported. We actually need do nothing on NT emulator
97 // environment. Classify this to follow EFI spec
102 // Other flush types are not supported by NT emulator
104 return EFI_UNSUPPORTED
;
110 WinNtEnableInterrupt (
111 IN EFI_CPU_ARCH_PROTOCOL
*This
117 This routine provides support for emulation of the interrupt enable of the
118 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
119 Architectural Protocol observes in order to defer behaviour while in its
120 emulated interrupt, or timer tick.
124 Pointer to CPU Architectural Protocol interface
132 // TODO: This - add argument and description to function comment
134 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
136 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
137 Private
->InterruptState
= TRUE
;
144 WinNtDisableInterrupt (
145 IN EFI_CPU_ARCH_PROTOCOL
*This
151 This routine provides support for emulation of the interrupt disable of the
152 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
153 Architectural Protocol observes in order to defer behaviour while in its
154 emulated interrupt, or timer tick.
158 Pointer to CPU Architectural Protocol interface
166 // TODO: This - add argument and description to function comment
168 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
170 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
171 Private
->InterruptState
= FALSE
;
178 WinNtGetInterruptState (
179 IN EFI_CPU_ARCH_PROTOCOL
*This
,
186 This routine provides support for emulation of the interrupt disable of the
187 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
188 Architectural Protocol observes in order to defer behaviour while in its
189 emulated interrupt, or timer tick.
193 Pointer to CPU Architectural Protocol interface
201 // TODO: This - add argument and description to function comment
202 // TODO: State - add argument and description to function comment
203 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
205 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
208 return EFI_INVALID_PARAMETER
;
211 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
212 *State
= Private
->InterruptState
;
220 IN EFI_CPU_ARCH_PROTOCOL
*This
,
221 IN EFI_CPU_INIT_TYPE InitType
227 This routine would support generation of a CPU INIT. At
228 present, this code does not provide emulation.
232 Pointer to CPU Architectural Protocol interface
238 EFI_UNSUPPORTED - not yet implemented
241 // TODO: This - add argument and description to function comment
242 // TODO: InitType - add argument and description to function comment
244 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
246 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
247 return EFI_UNSUPPORTED
;
253 WinNtRegisterInterruptHandler (
254 IN EFI_CPU_ARCH_PROTOCOL
*This
,
255 IN EFI_EXCEPTION_TYPE InterruptType
,
256 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
262 This routine would support registration of an interrupt handler. At
263 present, this code does not provide emulation.
267 Pointer to CPU Architectural Protocol interface
268 Pointer to interrupt handlers
274 EFI_UNSUPPORTED - not yet implemented
277 // TODO: This - add argument and description to function comment
278 // TODO: InterruptType - add argument and description to function comment
279 // TODO: InterruptHandler - add argument and description to function comment
281 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
284 // Do parameter checking for EFI spec conformance
286 if (InterruptType
< 0 || InterruptType
> 0xff) {
287 return EFI_UNSUPPORTED
;
290 // Do nothing for Nt32 emulation
292 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
293 return EFI_UNSUPPORTED
;
300 IN EFI_CPU_ARCH_PROTOCOL
*This
,
301 IN UINT32 TimerIndex
,
302 OUT UINT64
*TimerValue
,
303 OUT UINT64
*TimerPeriod OPTIONAL
309 This routine would support querying of an on-CPU timer. At present,
310 this code does not provide timer emulation.
314 This - Pointer to CPU Architectural Protocol interface
315 TimerIndex - Index of given CPU timer
316 TimerValue - Output of the timer
317 TimerPeriod - Output of the timer period
321 EFI_UNSUPPORTED - not yet implemented
322 EFI_INVALID_PARAMETER - TimeValue is NULL
326 if (TimerValue
== NULL
) {
327 return EFI_INVALID_PARAMETER
;
331 // No timer supported
333 return EFI_UNSUPPORTED
;
339 WinNtSetMemoryAttributes (
340 IN EFI_CPU_ARCH_PROTOCOL
*This
,
341 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
349 This routine would support querying of an on-CPU timer. At present,
350 this code does not provide timer emulation.
354 Pointer to CPU Architectural Protocol interface
355 Start address of memory region
356 The size in bytes of the memory region
357 The bit mask of attributes to set for the memory region
362 EFI_UNSUPPORTED - not yet implemented
365 // TODO: This - add argument and description to function comment
366 // TODO: BaseAddress - add argument and description to function comment
367 // TODO: Length - add argument and description to function comment
368 // TODO: Attributes - add argument and description to function comment
369 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
371 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
374 // Check for invalid parameter for Spec conformance
377 return EFI_INVALID_PARAMETER
;
381 // Do nothing for Nt32 emulation
383 Private
= CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This
);
384 return EFI_UNSUPPORTED
;
391 IN EFI_HANDLE ImageHandle
,
392 IN EFI_SYSTEM_TABLE
*SystemTable
398 Initialize the state information for the CPU Architectural Protocol
402 ImageHandle of the loaded driver
403 Pointer to the System Table
409 EFI_SUCCESS - protocol instance can be published
410 EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure
411 EFI_DEVICE_ERROR - cannot create the thread
414 // TODO: SystemTable - add argument and description to function comment
418 CPU_ARCH_PROTOCOL_PRIVATE
*Private
;
421 Private
= AllocatePool (sizeof (CPU_ARCH_PROTOCOL_PRIVATE
));
422 ASSERT (Private
!= NULL
);
424 Private
->Signature
= CPU_ARCH_PROT_PRIVATE_SIGNATURE
;
425 Private
->Cpu
.FlushDataCache
= WinNtFlushCpuDataCache
;
426 Private
->Cpu
.EnableInterrupt
= WinNtEnableInterrupt
;
427 Private
->Cpu
.DisableInterrupt
= WinNtDisableInterrupt
;
428 Private
->Cpu
.GetInterruptState
= WinNtGetInterruptState
;
429 Private
->Cpu
.Init
= WinNtInit
;
430 Private
->Cpu
.RegisterInterruptHandler
= WinNtRegisterInterruptHandler
;
431 Private
->Cpu
.GetTimerValue
= WinNtGetTimerValue
;
432 Private
->Cpu
.SetMemoryAttributes
= WinNtSetMemoryAttributes
;
434 Private
->Cpu
.NumberOfTimers
= 0;
435 Private
->Cpu
.DmaBufferAlignment
= 4;
437 Private
->InterruptState
= TRUE
;
439 Private
->CpuIo
.Mem
.Read
= CpuMemoryServiceRead
;
440 Private
->CpuIo
.Mem
.Write
= CpuMemoryServiceWrite
;
441 Private
->CpuIo
.Io
.Read
= CpuIoServiceRead
;
442 Private
->CpuIo
.Io
.Write
= CpuIoServiceWrite
;
445 Private
->Handle
= NULL
;
446 Status
= gBS
->InstallMultipleProtocolInterfaces (
448 &gEfiCpuArchProtocolGuid
, &Private
->Cpu
,
449 &gEfiCpuIoProtocolGuid
, &Private
->CpuIo
,
452 ASSERT_EFI_ERROR (Status
);
455 // Install notify function to store processor data to HII database and data hub.
457 Status
= gBS
->CreateEvent (
460 WinNtIoProtocolNotifyFunction
,
464 ASSERT (!EFI_ERROR (Status
));
466 Status
= gBS
->RegisterProtocolNotify (
467 &gEfiWinNtIoProtocolGuid
,
471 ASSERT (!EFI_ERROR (Status
));
474 // Should be at EFI_D_INFO, but lets us now things are running
476 DEBUG ((EFI_D_ERROR
, "CPU Architectural Protocol Loaded\n"));
490 Convert a unicode string to a UINTN
493 String - Unicode string.
496 UINTN of the number represented by String.
504 // skip preceeding white space
507 while ((*Str
) && (*Str
== ' ' || *Str
== '"')) {
511 // Convert ot a Number
514 while (*Str
!= '\0') {
515 if ((*Str
>= '0') && (*Str
<= '9')) {
516 Number
= (Number
* 10) +*Str
- '0';
529 WinNtIoProtocolNotifyFunction (
536 This function will log processor version and frequency data to data hub.
539 Event - Event whose notification function is being invoked.
540 Context - Pointer to the notification function's context.
548 EFI_CPU_DATA_RECORD_BUFFER RecordBuffer
;
549 EFI_DATA_RECORD_HEADER
*Record
;
550 EFI_SUBCLASS_TYPE1_HEADER
*DataHeader
;
555 UINT64 MonotonicCount
;
557 EFI_HANDLE
*HandleBuffer
;
558 EFI_WIN_NT_IO_PROTOCOL
*WinNtIo
;
559 EFI_DATA_HUB_PROTOCOL
*DataHub
;
560 EFI_HII_PROTOCOL
*Hii
;
561 EFI_HII_HANDLE StringHandle
;
562 EFI_HII_PACKAGES
*PackageList
;
571 // Retrieve the list of all handles from the handle database
573 Status
= gBS
->LocateHandleBuffer (
575 &gEfiWinNtIoProtocolGuid
,
580 if (EFI_ERROR (Status
)) {
584 // Locate HII protocol
586 Status
= gBS
->LocateProtocol (&gEfiHiiProtocolGuid
, NULL
, &Hii
);
587 if (EFI_ERROR (Status
)) {
591 // Locate DataHub protocol.
593 Status
= gBS
->LocateProtocol (&gEfiDataHubProtocolGuid
, NULL
, &DataHub
);
594 if (EFI_ERROR (Status
)) {
598 // Initialize data record header
600 mCpuDataRecordHeader
.Instance
= 1;
601 HeaderSize
= sizeof (EFI_SUBCLASS_TYPE1_HEADER
);
603 RecordBuffer
.Raw
= AllocatePool (HeaderSize
+ EFI_CPU_DATA_MAXIMUM_LENGTH
);
604 if (RecordBuffer
.Raw
== NULL
) {
608 CopyMem (RecordBuffer
.Raw
, &mCpuDataRecordHeader
, HeaderSize
);
611 // Search the Handle array to find the CPU model and speed information
613 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
614 Status
= gBS
->OpenProtocol (
615 HandleBuffer
[HandleIndex
],
616 &gEfiWinNtIoProtocolGuid
,
620 EFI_OPEN_PROTOCOL_GET_PROTOCOL
622 if (EFI_ERROR (Status
)) {
626 if ((WinNtIo
->WinNtThunk
->Signature
== EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE
) &&
627 CompareGuid (WinNtIo
->TypeGuid
, &gEfiWinNtCPUModelGuid
)
630 // Check if this record has been stored in data hub
633 Status
= DataHub
->GetNextRecord (DataHub
, &MonotonicCount
, NULL
, &Record
);
634 if (Record
->DataRecordClass
== EFI_DATA_RECORD_CLASS_DATA
) {
635 DataHeader
= (EFI_SUBCLASS_TYPE1_HEADER
*) (Record
+ 1);
636 if (CompareGuid (&Record
->DataRecordGuid
, &gEfiProcessorSubClassGuid
) &&
637 (DataHeader
->RecordType
== ProcessorVersionRecordType
)
642 } while (MonotonicCount
!= 0);
649 // Initialize strings to HII database
651 PackageList
= PreparePackages (1, &gEfiProcessorProducerGuid
, CpuStrings
);
653 Status
= Hii
->NewPack (Hii
, PackageList
, &StringHandle
);
654 ASSERT (!EFI_ERROR (Status
));
656 FreePool (PackageList
);
659 // Store processor version data record to data hub
661 Status
= Hii
->NewString (Hii
, NULL
, StringHandle
, &Token
, WinNtIo
->EnvString
);
662 ASSERT (!EFI_ERROR (Status
));
664 RecordBuffer
.DataRecord
->DataRecordHeader
.RecordType
= ProcessorVersionRecordType
;
665 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorVersion
= Token
;
666 TotalSize
= HeaderSize
+ sizeof (EFI_PROCESSOR_VERSION_DATA
);
668 Status
= DataHub
->LogData (
670 &gEfiProcessorSubClassGuid
,
671 &gEfiProcessorProducerGuid
,
672 EFI_DATA_RECORD_CLASS_DATA
,
678 if ((WinNtIo
->WinNtThunk
->Signature
== EFI_WIN_NT_THUNK_PROTOCOL_SIGNATURE
) &&
679 CompareGuid (WinNtIo
->TypeGuid
, &gEfiWinNtCPUSpeedGuid
)
682 // Check if this record has been stored in data hub
685 Status
= DataHub
->GetNextRecord (DataHub
, &MonotonicCount
, NULL
, &Record
);
686 if (Record
->DataRecordClass
== EFI_DATA_RECORD_CLASS_DATA
) {
687 DataHeader
= (EFI_SUBCLASS_TYPE1_HEADER
*) (Record
+ 1);
688 if (CompareGuid (&Record
->DataRecordGuid
, &gEfiProcessorSubClassGuid
) &&
689 (DataHeader
->RecordType
== ProcessorCoreFrequencyRecordType
)
694 } while (MonotonicCount
!= 0);
701 // Store CPU frequency data record to data hub
703 RecordBuffer
.DataRecord
->DataRecordHeader
.RecordType
= ProcessorCoreFrequencyRecordType
;
704 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorCoreFrequency
.Value
= (UINT16
) Atoi (WinNtIo
->EnvString
);
705 RecordBuffer
.DataRecord
->VariableRecord
.ProcessorCoreFrequency
.Exponent
= 6;
706 TotalSize
= HeaderSize
+ sizeof (EFI_PROCESSOR_CORE_FREQUENCY_DATA
);
708 Status
= DataHub
->LogData (
710 &gEfiProcessorSubClassGuid
,
711 &gEfiProcessorProducerGuid
,
712 EFI_DATA_RECORD_CLASS_DATA
,
717 FreePool (RecordBuffer
.Raw
);
721 HandleBuffer
[HandleIndex
],
722 &gEfiWinNtIoProtocolGuid
,