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