]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/CpuRuntimeDxe/Cpu.c
According to PI errata 0000654 and 000811, we need use 0xFFFE to instead of 0 for...
[mirror_edk2.git] / UnixPkg / CpuRuntimeDxe / Cpu.c
1 /*++
2
3 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
4 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 #include <FrameworkDxe.h>
25 #include <IndustryStandard/SmBios.h>
26 #include <Protocol/Cpu.h>
27 #include <Protocol/Smbios.h>
28 #include <Guid/DataHubRecords.h>
29 #include <Protocol/CpuIo2.h>
30 #include <Protocol/FrameworkHii.h>
31 #include <Protocol/UnixThunk.h>
32
33 #include <Library/BaseLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/HiiLib.h>
36 #include <Library/UefiLib.h>
37 #include <Library/UefiDriverEntryPoint.h>
38 #include <Library/BaseMemoryLib.h>
39 #include <Library/MemoryAllocationLib.h>
40 #include <Library/UefiBootServicesTableLib.h>
41 #include <Library/UnixLib.h>
42
43 #include "CpuDriver.h"
44 #include "UnixDxe.h"
45 #include <Protocol/UnixIo.h>
46
47 #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100
48
49 CPU_ARCH_PROTOCOL_PRIVATE mCpuTemplate = {
50 CPU_ARCH_PROT_PRIVATE_SIGNATURE,
51 NULL,
52 {
53 UnixFlushCpuDataCache,
54 UnixEnableInterrupt,
55 UnixDisableInterrupt,
56 UnixGetInterruptState,
57 UnixInit,
58 UnixRegisterInterruptHandler,
59 UnixGetTimerValue,
60 UnixSetMemoryAttributes,
61 0,
62 4
63 },
64 {
65 {
66 CpuMemoryServiceRead,
67 CpuMemoryServiceWrite
68 },
69 {
70 CpuIoServiceRead,
71 CpuIoServiceWrite
72 }
73 },
74 TRUE
75 };
76
77
78 //
79 // Service routines for the driver
80 //
81 EFI_STATUS
82 EFIAPI
83 UnixFlushCpuDataCache (
84 IN EFI_CPU_ARCH_PROTOCOL *This,
85 IN EFI_PHYSICAL_ADDRESS Start,
86 IN UINT64 Length,
87 IN EFI_CPU_FLUSH_TYPE FlushType
88 )
89 /*++
90
91 Routine Description:
92
93 This routine would provide support for flushing the CPU data cache.
94 In the case of UNIX emulation environment, this flushing is not necessary and
95 is thus not implemented.
96
97 Arguments:
98
99 Pointer to CPU Architectural Protocol interface
100 Start adddress in memory to flush
101 Length of memory to flush
102 Flush type
103
104 Returns:
105
106 Status
107 EFI_SUCCESS
108
109 --*/
110 // TODO: This - add argument and description to function comment
111 // TODO: FlushType - add argument and description to function comment
112 // TODO: EFI_UNSUPPORTED - add return value to function comment
113 {
114 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
115 //
116 // Only WB flush is supported. We actually need do nothing on UNIX emulator
117 // environment. Classify this to follow EFI spec
118 //
119 return EFI_SUCCESS;
120 }
121 //
122 // Other flush types are not supported by UNIX emulator
123 //
124 return EFI_UNSUPPORTED;
125 }
126
127 EFI_STATUS
128 EFIAPI
129 UnixEnableInterrupt (
130 IN EFI_CPU_ARCH_PROTOCOL *This
131 )
132 /*++
133
134 Routine Description:
135
136 This routine provides support for emulation of the interrupt enable of the
137 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
138 Architectural Protocol observes in order to defer behaviour while in its
139 emulated interrupt, or timer tick.
140
141 Arguments:
142
143 Pointer to CPU Architectural Protocol interface
144
145 Returns:
146
147 Status
148 EFI_SUCCESS
149
150 --*/
151 // TODO: This - add argument and description to function comment
152 {
153 CPU_ARCH_PROTOCOL_PRIVATE *Private;
154
155 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
156 Private->InterruptState = TRUE;
157 gUnix->EnableInterrupt ();
158 return EFI_SUCCESS;
159 }
160
161 EFI_STATUS
162 EFIAPI
163 UnixDisableInterrupt (
164 IN EFI_CPU_ARCH_PROTOCOL *This
165 )
166 /*++
167
168 Routine Description:
169
170 This routine provides support for emulation of the interrupt disable of the
171 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
172 Architectural Protocol observes in order to defer behaviour while in its
173 emulated interrupt, or timer tick.
174
175 Arguments:
176
177 Pointer to CPU Architectural Protocol interface
178
179 Returns:
180
181 Status
182 EFI_SUCCESS
183
184 --*/
185 // TODO: This - add argument and description to function comment
186 {
187 CPU_ARCH_PROTOCOL_PRIVATE *Private;
188
189 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
190 Private->InterruptState = FALSE;
191 gUnix->DisableInterrupt ();
192 return EFI_SUCCESS;
193 }
194
195 EFI_STATUS
196 EFIAPI
197 UnixGetInterruptState (
198 IN EFI_CPU_ARCH_PROTOCOL *This,
199 OUT BOOLEAN *State
200 )
201 /*++
202
203 Routine Description:
204
205 This routine provides support for emulation of the interrupt disable of the
206 the system. For our purposes, CPU enable is just a BOOLEAN that the Timer
207 Architectural Protocol observes in order to defer behaviour while in its
208 emulated interrupt, or timer tick.
209
210 Arguments:
211
212 Pointer to CPU Architectural Protocol interface
213
214 Returns:
215
216 Status
217 EFI_SUCCESS
218
219 --*/
220 // TODO: This - add argument and description to function comment
221 // TODO: State - add argument and description to function comment
222 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
223 {
224 CPU_ARCH_PROTOCOL_PRIVATE *Private;
225
226 if (State == NULL) {
227 return EFI_INVALID_PARAMETER;
228 }
229
230 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
231 *State = Private->InterruptState;
232 return EFI_SUCCESS;
233 }
234
235 EFI_STATUS
236 EFIAPI
237 UnixInit (
238 IN EFI_CPU_ARCH_PROTOCOL *This,
239 IN EFI_CPU_INIT_TYPE InitType
240 )
241 /*++
242
243 Routine Description:
244
245 This routine would support generation of a CPU INIT. At
246 present, this code does not provide emulation.
247
248 Arguments:
249
250 Pointer to CPU Architectural Protocol interface
251 INIT Type
252
253 Returns:
254
255 Status
256 EFI_UNSUPPORTED - not yet implemented
257
258 --*/
259 // TODO: This - add argument and description to function comment
260 // TODO: InitType - add argument and description to function comment
261 {
262 CPU_ARCH_PROTOCOL_PRIVATE *Private;
263
264 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
265 return EFI_UNSUPPORTED;
266 }
267
268 EFI_STATUS
269 EFIAPI
270 UnixRegisterInterruptHandler (
271 IN EFI_CPU_ARCH_PROTOCOL *This,
272 IN EFI_EXCEPTION_TYPE InterruptType,
273 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
274 )
275 /*++
276
277 Routine Description:
278
279 This routine would support registration of an interrupt handler. At
280 present, this code does not provide emulation.
281
282 Arguments:
283
284 Pointer to CPU Architectural Protocol interface
285 Pointer to interrupt handlers
286 Interrupt type
287
288 Returns:
289
290 Status
291 EFI_UNSUPPORTED - not yet implemented
292
293 --*/
294 // TODO: This - add argument and description to function comment
295 // TODO: InterruptType - add argument and description to function comment
296 // TODO: InterruptHandler - add argument and description to function comment
297 {
298 CPU_ARCH_PROTOCOL_PRIVATE *Private;
299
300 //
301 // Do parameter checking for EFI spec conformance
302 //
303 if (InterruptType < 0 || InterruptType > 0xff) {
304 return EFI_UNSUPPORTED;
305 }
306 //
307 // Do nothing for Nt32 emulation
308 //
309 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
310 return EFI_UNSUPPORTED;
311 }
312
313 EFI_STATUS
314 EFIAPI
315 UnixGetTimerValue (
316 IN EFI_CPU_ARCH_PROTOCOL *This,
317 IN UINT32 TimerIndex,
318 OUT UINT64 *TimerValue,
319 OUT UINT64 *TimerPeriod OPTIONAL
320 )
321 /*++
322
323 Routine Description:
324
325 This routine would support querying of an on-CPU timer. At present,
326 this code does not provide timer emulation.
327
328 Arguments:
329
330 This - Pointer to CPU Architectural Protocol interface
331 TimerIndex - Index of given CPU timer
332 TimerValue - Output of the timer
333 TimerPeriod - Output of the timer period
334
335 Returns:
336
337 EFI_UNSUPPORTED - not yet implemented
338 EFI_INVALID_PARAMETER - TimeValue is NULL
339
340 --*/
341 {
342 if (TimerValue == NULL) {
343 return EFI_INVALID_PARAMETER;
344 }
345
346 //
347 // No timer supported
348 //
349 return EFI_UNSUPPORTED;
350 }
351
352 EFI_STATUS
353 EFIAPI
354 UnixSetMemoryAttributes (
355 IN EFI_CPU_ARCH_PROTOCOL *This,
356 IN EFI_PHYSICAL_ADDRESS BaseAddress,
357 IN UINT64 Length,
358 IN UINT64 Attributes
359 )
360 /*++
361
362 Routine Description:
363
364 This routine would support querying of an on-CPU timer. At present,
365 this code does not provide timer emulation.
366
367 Arguments:
368
369 Pointer to CPU Architectural Protocol interface
370 Start address of memory region
371 The size in bytes of the memory region
372 The bit mask of attributes to set for the memory region
373
374 Returns:
375
376 Status
377 EFI_UNSUPPORTED - not yet implemented
378
379 --*/
380 // TODO: This - add argument and description to function comment
381 // TODO: BaseAddress - add argument and description to function comment
382 // TODO: Length - add argument and description to function comment
383 // TODO: Attributes - add argument and description to function comment
384 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
385 {
386 CPU_ARCH_PROTOCOL_PRIVATE *Private;
387
388 //
389 // Check for invalid parameter for Spec conformance
390 //
391 if (Length == 0) {
392 return EFI_INVALID_PARAMETER;
393 }
394
395 //
396 // Do nothing for Nt32 emulation
397 //
398 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
399 return EFI_UNSUPPORTED;
400 }
401
402
403
404 /**
405 Logs SMBIOS record.
406
407 @param Smbios Pointer to SMBIOS protocol instance.
408 @param Buffer Pointer to the data buffer.
409
410 **/
411 VOID
412 LogSmbiosData (
413 IN EFI_SMBIOS_PROTOCOL *Smbios,
414 IN UINT8 *Buffer
415 )
416 {
417 EFI_STATUS Status;
418 EFI_SMBIOS_HANDLE SmbiosHandle;
419
420 SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
421 Status = Smbios->Add (
422 Smbios,
423 NULL,
424 &SmbiosHandle,
425 (EFI_SMBIOS_TABLE_HEADER*)Buffer
426 );
427 ASSERT_EFI_ERROR (Status);
428 }
429
430 VOID
431 CpuUpdateSmbios (
432 VOID
433 )
434 /*++
435
436 Routine Description:
437 This function will log processor version and frequency data to data hub.
438
439 Arguments:
440 Event - Event whose notification function is being invoked.
441 Context - Pointer to the notification function's context.
442
443 Returns:
444 None.
445
446 --*/
447 {
448 EFI_STATUS Status;
449 EFI_SMBIOS_PROTOCOL *Smbios;
450 UINT32 TotalSize;
451 EFI_HII_HANDLE HiiHandle;
452 STRING_REF Token;
453 UINTN CpuVerStrLen;
454 EFI_STRING CpuVerStr;
455 SMBIOS_TABLE_TYPE4 *SmbiosRecord;
456 CHAR8 *OptionalStrStart;
457
458 //
459 // Locate Smbios protocol.
460 //
461 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios);
462
463 if (EFI_ERROR (Status)) {
464 return;
465 }
466
467 //
468 // Initialize strings to HII database
469 //
470 HiiHandle = HiiAddPackages (
471 &gEfiCallerIdGuid,
472 NULL,
473 CpuStrings,
474 NULL
475 );
476 ASSERT (HiiHandle != NULL);
477
478
479 Token = STRING_TOKEN (STR_INTEL_GENUINE_PROCESSOR);
480 CpuVerStr = HiiGetPackageString(&gEfiCallerIdGuid, Token, NULL);
481 CpuVerStrLen = StrLen(CpuVerStr);
482 ASSERT (CpuVerStrLen <= SMBIOS_STRING_MAX_LENGTH);
483
484 TotalSize = sizeof(SMBIOS_TABLE_TYPE4) + CpuVerStrLen + 1 + 1;
485 SmbiosRecord = AllocatePool(TotalSize);
486 ZeroMem(SmbiosRecord, TotalSize);
487
488 SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION;
489 SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4);
490 //
491 // Make handle chosen by smbios protocol.add automatically.
492 //
493 SmbiosRecord->Hdr.Handle = 0;
494 //
495 // Processor version is the 1st string.
496 //
497 SmbiosRecord->ProcessorVersion = 1;
498 //
499 // Store CPU frequency data record to data hub - It's an emulator so make up a value
500 //
501 SmbiosRecord->CurrentSpeed = 1234;
502
503 OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1);
504 UnicodeStrToAsciiStr(CpuVerStr, OptionalStrStart);
505
506 //
507 // Now we have got the full smbios record, call smbios protocol to add this record.
508 //
509 LogSmbiosData(Smbios, (UINT8 *) SmbiosRecord);
510 FreePool (SmbiosRecord);
511 }
512
513 EFI_STATUS
514 EFIAPI
515 InitializeCpu (
516 IN EFI_HANDLE ImageHandle,
517 IN EFI_SYSTEM_TABLE *SystemTable
518 )
519 /*++
520
521 Routine Description:
522
523 Initialize the state information for the CPU Architectural Protocol
524
525 Arguments:
526
527 ImageHandle of the loaded driver
528 Pointer to the System Table
529
530 Returns:
531
532 Status
533
534 EFI_SUCCESS - protocol instance can be published
535 EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure
536 EFI_DEVICE_ERROR - cannot create the thread
537
538 --*/
539 // TODO: SystemTable - add argument and description to function comment
540 {
541 EFI_STATUS Status;
542
543 CpuUpdateSmbios ();
544
545 Status = gBS->InstallMultipleProtocolInterfaces (
546 &mCpuTemplate.Handle,
547 &gEfiCpuArchProtocolGuid, &mCpuTemplate.Cpu,
548 &gEfiCpuIo2ProtocolGuid, &mCpuTemplate.CpuIo,
549 NULL
550 );
551 ASSERT_EFI_ERROR (Status);
552
553 DEBUG ((EFI_D_ERROR, "CPU Architectural Protocol Loaded\n"));
554
555 return Status;
556 }