]> git.proxmox.com Git - mirror_edk2.git/blob - EdkUnixPkg/Dxe/UnixThunk/Cpu/Cpu.c
9149639abce5fe9cb558d4c7c3361839f22582c7
[mirror_edk2.git] / EdkUnixPkg / Dxe / UnixThunk / Cpu / Cpu.c
1 /*++
2
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
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 Unix 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 UnixIoProtocolNotifyFunction (
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 UnixFlushCpuDataCache (
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 UnixEnableInterrupt (
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 UnixDisableInterrupt (
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 UnixGetInterruptState (
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 UnixInit (
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 UnixRegisterInterruptHandler (
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 UnixGetTimerValue (
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 UnixSetMemoryAttributes (
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 Status = gBS->AllocatePool (
421 EfiBootServicesData,
422 sizeof (CPU_ARCH_PROTOCOL_PRIVATE),
423 (VOID **)&Private
424 );
425 ASSERT_EFI_ERROR (Status);
426
427 Private->Signature = CPU_ARCH_PROT_PRIVATE_SIGNATURE;
428 Private->Cpu.FlushDataCache = UnixFlushCpuDataCache;
429 Private->Cpu.EnableInterrupt = UnixEnableInterrupt;
430 Private->Cpu.DisableInterrupt = UnixDisableInterrupt;
431 Private->Cpu.GetInterruptState = UnixGetInterruptState;
432 Private->Cpu.Init = UnixInit;
433 Private->Cpu.RegisterInterruptHandler = UnixRegisterInterruptHandler;
434 Private->Cpu.GetTimerValue = UnixGetTimerValue;
435 Private->Cpu.SetMemoryAttributes = UnixSetMemoryAttributes;
436
437 Private->Cpu.NumberOfTimers = 0;
438 Private->Cpu.DmaBufferAlignment = 4;
439
440 Private->InterruptState = TRUE;
441
442 Private->CpuIo.Mem.Read = CpuMemoryServiceRead;
443 Private->CpuIo.Mem.Write = CpuMemoryServiceWrite;
444 Private->CpuIo.Io.Read = CpuIoServiceRead;
445 Private->CpuIo.Io.Write = CpuIoServiceWrite;
446
447
448 Private->Handle = NULL;
449 Status = gBS->InstallMultipleProtocolInterfaces (
450 &Private->Handle,
451 &gEfiCpuArchProtocolGuid, &Private->Cpu,
452 &gEfiCpuIoProtocolGuid, &Private->CpuIo,
453 NULL
454 );
455 ASSERT_EFI_ERROR (Status);
456
457 //
458 // Install notify function to store processor data to HII database and data hub.
459 //
460 Status = gBS->CreateEvent (
461 EFI_EVENT_NOTIFY_SIGNAL,
462 EFI_TPL_CALLBACK,
463 UnixIoProtocolNotifyFunction,
464 ImageHandle,
465 &Event
466 );
467 ASSERT (!EFI_ERROR (Status));
468
469 Status = gBS->RegisterProtocolNotify (
470 &gEfiUnixIoProtocolGuid,
471 Event,
472 &Registration
473 );
474 ASSERT (!EFI_ERROR (Status));
475
476 //
477 // Should be at EFI_D_INFO, but lets us now things are running
478 //
479 DEBUG ((EFI_D_ERROR, "CPU Architectural Protocol Loaded\n"));
480
481
482
483 return Status;
484 }
485
486 UINTN
487 Atoi (
488 UINT16 *String
489 )
490 /*++
491
492 Routine Description:
493 Convert a unicode string to a UINTN
494
495 Arguments:
496 String - Unicode string.
497
498 Returns:
499 UINTN of the number represented by String.
500
501 --*/
502 {
503 UINTN Number;
504 UINT16 *Str;
505
506 //
507 // skip preceeding white space
508 //
509 Str = String;
510 while ((*Str) && (*Str == ' ' || *Str == '"')) {
511 Str++;
512 }
513 //
514 // Convert ot a Number
515 //
516 Number = 0;
517 while (*Str != '\0') {
518 if ((*Str >= '0') && (*Str <= '9')) {
519 Number = (Number * 10) +*Str - '0';
520 } else {
521 break;
522 }
523
524 Str++;
525 }
526
527 return Number;
528 }
529
530 VOID
531 EFIAPI
532 UnixIoProtocolNotifyFunction (
533 IN EFI_EVENT Event,
534 IN VOID *Context
535 )
536 /*++
537
538 Routine Description:
539 This function will log processor version and frequency data to data hub.
540
541 Arguments:
542 Event - Event whose notification function is being invoked.
543 Context - Pointer to the notification function's context.
544
545 Returns:
546 None.
547
548 --*/
549 {
550 EFI_STATUS Status;
551 EFI_CPU_DATA_RECORD_BUFFER RecordBuffer;
552 EFI_DATA_RECORD_HEADER *Record;
553 EFI_SUBCLASS_TYPE1_HEADER *DataHeader;
554 UINT32 HeaderSize;
555 UINT32 TotalSize;
556 UINTN HandleCount;
557 UINTN HandleIndex;
558 UINT64 MonotonicCount;
559 BOOLEAN RecordFound;
560 EFI_HANDLE *HandleBuffer;
561 EFI_UNIX_IO_PROTOCOL *UnixIo;
562 EFI_DATA_HUB_PROTOCOL *DataHub;
563 EFI_HII_PROTOCOL *Hii;
564 EFI_HII_HANDLE StringHandle;
565 EFI_HII_PACKAGES *PackageList;
566 STRING_REF Token;
567
568 DataHub = NULL;
569 Token = 0;
570 MonotonicCount = 0;
571 RecordFound = FALSE;
572
573 //
574 // Retrieve the list of all handles from the handle database
575 //
576 Status = gBS->LocateHandleBuffer (
577 AllHandles,
578 &gEfiUnixIoProtocolGuid,
579 NULL,
580 &HandleCount,
581 &HandleBuffer
582 );
583 if (EFI_ERROR (Status)) {
584 return ;
585 }
586 //
587 // Locate HII protocol
588 //
589 Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, (VOID **)&Hii);
590 if (EFI_ERROR (Status)) {
591 return ;
592 }
593 //
594 // Locate DataHub protocol.
595 //
596 Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (VOID **)&DataHub);
597 if (EFI_ERROR (Status)) {
598 return ;
599 }
600 //
601 // Initialize data record header
602 //
603 mCpuDataRecordHeader.Instance = 1;
604 HeaderSize = sizeof (EFI_SUBCLASS_TYPE1_HEADER);
605
606 RecordBuffer.Raw = AllocatePool (HeaderSize + EFI_CPU_DATA_MAXIMUM_LENGTH);
607 if (RecordBuffer.Raw == NULL) {
608 return ;
609 }
610
611 CopyMem (RecordBuffer.Raw, &mCpuDataRecordHeader, HeaderSize);
612
613 //
614 // Search the Handle array to find the CPU model and speed information
615 //
616 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
617 Status = gBS->OpenProtocol (
618 HandleBuffer[HandleIndex],
619 &gEfiUnixIoProtocolGuid,
620 (VOID **)&UnixIo,
621 Context,
622 NULL,
623 EFI_OPEN_PROTOCOL_GET_PROTOCOL
624 );
625 if (EFI_ERROR (Status)) {
626 continue;
627 }
628
629 if ((UnixIo->UnixThunk->Signature == EFI_UNIX_THUNK_PROTOCOL_SIGNATURE) &&
630 CompareGuid (UnixIo->TypeGuid, &gEfiUnixCPUModelGuid)
631 ) {
632 //
633 // Check if this record has been stored in data hub
634 //
635 do {
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)
641 ) {
642 RecordFound = TRUE;
643 }
644 }
645 } while (MonotonicCount != 0);
646
647 if (RecordFound) {
648 RecordFound = FALSE;
649 continue;
650 }
651 //
652 // Initialize strings to HII database
653 //
654 PackageList = PreparePackages (1, &gEfiProcessorProducerGuid, STRING_ARRAY_NAME);
655
656 Status = Hii->NewPack (Hii, PackageList, &StringHandle);
657 ASSERT (!EFI_ERROR (Status));
658
659 gBS->FreePool (PackageList);
660
661 //
662 // Store processor version data record to data hub
663 //
664 Status = Hii->NewString (Hii, NULL, StringHandle, &Token, UnixIo->EnvString);
665 ASSERT (!EFI_ERROR (Status));
666
667 RecordBuffer.DataRecord->DataRecordHeader.RecordType = ProcessorVersionRecordType;
668 RecordBuffer.DataRecord->VariableRecord.ProcessorVersion = Token;
669 TotalSize = HeaderSize + sizeof (EFI_PROCESSOR_VERSION_DATA);
670
671 Status = DataHub->LogData (
672 DataHub,
673 &gEfiProcessorSubClassGuid,
674 &gEfiProcessorProducerGuid,
675 EFI_DATA_RECORD_CLASS_DATA,
676 RecordBuffer.Raw,
677 TotalSize
678 );
679 }
680
681 if ((UnixIo->UnixThunk->Signature == EFI_UNIX_THUNK_PROTOCOL_SIGNATURE) &&
682 CompareGuid (UnixIo->TypeGuid, &gEfiUnixCPUSpeedGuid)
683 ) {
684 //
685 // Check if this record has been stored in data hub
686 //
687 do {
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)
693 ) {
694 RecordFound = TRUE;
695 }
696 }
697 } while (MonotonicCount != 0);
698
699 if (RecordFound) {
700 RecordFound = FALSE;
701 continue;
702 }
703 //
704 // Store CPU frequency data record to data hub
705 //
706 RecordBuffer.DataRecord->DataRecordHeader.RecordType = ProcessorCoreFrequencyRecordType;
707 RecordBuffer.DataRecord->VariableRecord.ProcessorCoreFrequency.Value = (UINT16) Atoi (UnixIo->EnvString);
708 RecordBuffer.DataRecord->VariableRecord.ProcessorCoreFrequency.Exponent = 6;
709 TotalSize = HeaderSize + sizeof (EFI_PROCESSOR_CORE_FREQUENCY_DATA);
710
711 Status = DataHub->LogData (
712 DataHub,
713 &gEfiProcessorSubClassGuid,
714 &gEfiProcessorProducerGuid,
715 EFI_DATA_RECORD_CLASS_DATA,
716 RecordBuffer.Raw,
717 TotalSize
718 );
719
720 gBS->FreePool (RecordBuffer.Raw);
721 }
722
723 gBS->CloseProtocol (
724 HandleBuffer[HandleIndex],
725 &gEfiUnixIoProtocolGuid,
726 Context,
727 NULL
728 );
729 }
730 }