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