]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/CpuRuntimeDxe/Cpu.c
EmulatorPkg: Change the cpu frequency to a non-zero value
[mirror_edk2.git] / EmulatorPkg / CpuRuntimeDxe / Cpu.c
1 /*++ @file
2 Emu driver to produce CPU Architectural Protocol.
3
4 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2011 - 2012, Apple Inc. All rights reserved.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "CpuDriver.h"
11
12 UINT64 mTimerPeriod;
13
14 CPU_ARCH_PROTOCOL_PRIVATE mCpuTemplate = {
15 CPU_ARCH_PROT_PRIVATE_SIGNATURE,
16 NULL,
17 {
18 EmuFlushCpuDataCache,
19 EmuEnableInterrupt,
20 EmuDisableInterrupt,
21 EmuGetInterruptState,
22 EmuInit,
23 EmuRegisterInterruptHandler,
24 EmuGetTimerValue,
25 EmuSetMemoryAttributes,
26 0,
27 4
28 },
29 {
30 {
31 CpuMemoryServiceRead,
32 CpuMemoryServiceWrite
33 },
34 {
35 CpuIoServiceRead,
36 CpuIoServiceWrite
37 }
38 },
39 TRUE
40 };
41
42 #define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100
43
44 SMBIOS_TABLE_TYPE4 mCpuSmbiosType4 = {
45 { EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION, sizeof (SMBIOS_TABLE_TYPE4), 0},
46 1, // Socket String
47 ProcessorOther, // ProcessorType; ///< The enumeration value from PROCESSOR_TYPE_DATA.
48 ProcessorFamilyOther, // ProcessorFamily; ///< The enumeration value from PROCESSOR_FAMILY_DATA.
49 2, // ProcessorManufacture String;
50 { // ProcessorId;
51 { // PROCESSOR_SIGNATURE
52 0, // ProcessorSteppingId:4;
53 0, // ProcessorModel: 4;
54 0, // ProcessorFamily: 4;
55 0, // ProcessorType: 2;
56 0, // ProcessorReserved1: 2;
57 0, // ProcessorXModel: 4;
58 0, // ProcessorXFamily: 8;
59 0, // ProcessorReserved2: 4;
60 },
61 { // PROCESSOR_FEATURE_FLAGS
62 0, // ProcessorFpu :1;
63 0, // ProcessorVme :1;
64 0, // ProcessorDe :1;
65 0, // ProcessorPse :1;
66 0, // ProcessorTsc :1;
67 0, // ProcessorMsr :1;
68 0, // ProcessorPae :1;
69 0, // ProcessorMce :1;
70 0, // ProcessorCx8 :1;
71 0, // ProcessorApic :1;
72 0, // ProcessorReserved1 :1;
73 0, // ProcessorSep :1;
74 0, // ProcessorMtrr :1;
75 0, // ProcessorPge :1;
76 0, // ProcessorMca :1;
77 0, // ProcessorCmov :1;
78 0, // ProcessorPat :1;
79 0, // ProcessorPse36 :1;
80 0, // ProcessorPsn :1;
81 0, // ProcessorClfsh :1;
82 0, // ProcessorReserved2 :1;
83 0, // ProcessorDs :1;
84 0, // ProcessorAcpi :1;
85 0, // ProcessorMmx :1;
86 0, // ProcessorFxsr :1;
87 0, // ProcessorSse :1;
88 0, // ProcessorSse2 :1;
89 0, // ProcessorSs :1;
90 0, // ProcessorReserved3 :1;
91 0, // ProcessorTm :1;
92 0, // ProcessorReserved4 :2;
93 }
94 },
95 3, // ProcessorVersion String;
96 { // Voltage;
97 1, // ProcessorVoltageCapability5V :1;
98 1, // ProcessorVoltageCapability3_3V :1;
99 1, // ProcessorVoltageCapability2_9V :1;
100 0, // ProcessorVoltageCapabilityReserved :1; ///< Bit 3, must be zero.
101 0, // ProcessorVoltageReserved :3; ///< Bits 4-6, must be zero.
102 0 // ProcessorVoltageIndicateLegacy :1;
103 },
104 0, // ExternalClock;
105 0, // MaxSpeed;
106 0, // CurrentSpeed;
107 0x41, // Status;
108 ProcessorUpgradeOther, // ProcessorUpgrade; ///< The enumeration value from PROCESSOR_UPGRADE.
109 0, // L1CacheHandle;
110 0, // L2CacheHandle;
111 0, // L3CacheHandle;
112 4, // SerialNumber;
113 5, // AssetTag;
114 6, // PartNumber;
115 0, // CoreCount;
116 0, // EnabledCoreCount;
117 0, // ThreadCount;
118 0, // ProcessorCharacteristics;
119 0, // ProcessorFamily2;
120 };
121
122 CHAR8 *mCpuSmbiosType4Strings[] = {
123 "Socket",
124 "http://www.tianocore.org/edk2/",
125 "Emulated Processor",
126 "1.0",
127 "1.0",
128 "1.0",
129 NULL
130 };
131
132
133 /**
134 Create SMBIOS record.
135
136 Converts a fixed SMBIOS structure and an array of pointers to strings into
137 an SMBIOS record where the strings are cat'ed on the end of the fixed record
138 and terminated via a double NULL and add to SMBIOS table.
139
140 SMBIOS_TABLE_TYPE32 gSmbiosType12 = {
141 { EFI_SMBIOS_TYPE_SYSTEM_CONFIGURATION_OPTIONS, sizeof (SMBIOS_TABLE_TYPE12), 0 },
142 1 // StringCount
143 };
144 CHAR8 *gSmbiosType12Strings[] = {
145 "Not Found",
146 NULL
147 };
148
149 ...
150 LogSmbiosData (
151 (EFI_SMBIOS_TABLE_HEADER*)&gSmbiosType12,
152 gSmbiosType12Strings
153 );
154
155 @param Template Fixed SMBIOS structure, required.
156 @param StringArray Array of strings to convert to an SMBIOS string pack.
157 NULL is OK.
158
159 **/
160 EFI_STATUS
161 LogSmbiosData (
162 IN EFI_SMBIOS_TABLE_HEADER *Template,
163 IN CHAR8 **StringPack
164 )
165 {
166 EFI_STATUS Status;
167 EFI_SMBIOS_PROTOCOL *Smbios;
168 EFI_SMBIOS_HANDLE SmbiosHandle;
169 EFI_SMBIOS_TABLE_HEADER *Record;
170 UINTN Index;
171 UINTN StringSize;
172 UINTN Size;
173 CHAR8 *Str;
174
175 //
176 // Locate Smbios protocol.
177 //
178 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios);
179 if (EFI_ERROR (Status)) {
180 return Status;
181 }
182
183 // Calculate the size of the fixed record and optional string pack
184 Size = Template->Length;
185 if (StringPack == NULL) {
186 // At least a double null is required
187 Size += 2;
188 } else {
189 for (Index = 0; StringPack[Index] != NULL; Index++) {
190 StringSize = AsciiStrSize (StringPack[Index]);
191 Size += StringSize;
192 }
193 if (StringPack[0] == NULL) {
194 // At least a double null is required
195 Size += 1;
196 }
197 // Don't forget the terminating double null
198 Size += 1;
199 }
200
201 // Copy over Template
202 Record = (EFI_SMBIOS_TABLE_HEADER *)AllocateZeroPool (Size);
203 if (Record == NULL) {
204 return EFI_OUT_OF_RESOURCES;
205 }
206 CopyMem (Record, Template, Template->Length);
207
208 // Append string pack
209 Str = ((CHAR8 *)Record) + Record->Length;
210 for (Index = 0; StringPack[Index] != NULL; Index++) {
211 StringSize = AsciiStrSize (StringPack[Index]);
212 CopyMem (Str, StringPack[Index], StringSize);
213 Str += StringSize;
214 }
215 *Str = 0;
216
217 SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
218 Status = Smbios->Add (
219 Smbios,
220 gImageHandle,
221 &SmbiosHandle,
222 Record
223 );
224 ASSERT_EFI_ERROR (Status);
225
226 FreePool (Record);
227 return Status;
228 }
229
230
231
232
233 VOID
234 CpuUpdateSmbios (
235 IN UINTN MaxCpus
236 )
237 {
238 mCpuSmbiosType4.CoreCount = (UINT8) MaxCpus;
239 mCpuSmbiosType4.EnabledCoreCount = (UINT8) MaxCpus;
240 mCpuSmbiosType4.ThreadCount = (UINT8) MaxCpus;
241 //
242 // The value of 1234 is fake value for CPU frequency
243 //
244 mCpuSmbiosType4.CurrentSpeed = 1234;
245 LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mCpuSmbiosType4, mCpuSmbiosType4Strings);
246 }
247
248
249 //
250 // Service routines for the driver
251 //
252 EFI_STATUS
253 EFIAPI
254 EmuFlushCpuDataCache (
255 IN EFI_CPU_ARCH_PROTOCOL *This,
256 IN EFI_PHYSICAL_ADDRESS Start,
257 IN UINT64 Length,
258 IN EFI_CPU_FLUSH_TYPE FlushType
259 )
260 {
261 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
262 //
263 // Only WB flush is supported. We actually need do nothing on Emu emulator
264 // environment. Classify this to follow EFI spec
265 //
266 return EFI_SUCCESS;
267 }
268 //
269 // Other flush types are not supported by Emu emulator
270 //
271 return EFI_UNSUPPORTED;
272 }
273
274 EFI_STATUS
275 EFIAPI
276 EmuEnableInterrupt (
277 IN EFI_CPU_ARCH_PROTOCOL *This
278 )
279 {
280 CPU_ARCH_PROTOCOL_PRIVATE *Private;
281
282 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
283 Private->InterruptState = TRUE;
284 gEmuThunk->EnableInterrupt ();
285 return EFI_SUCCESS;
286 }
287
288 EFI_STATUS
289 EFIAPI
290 EmuDisableInterrupt (
291 IN EFI_CPU_ARCH_PROTOCOL *This
292 )
293 {
294 CPU_ARCH_PROTOCOL_PRIVATE *Private;
295
296 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
297 Private->InterruptState = FALSE;
298 gEmuThunk->DisableInterrupt ();
299 return EFI_SUCCESS;
300 }
301
302 EFI_STATUS
303 EFIAPI
304 EmuGetInterruptState (
305 IN EFI_CPU_ARCH_PROTOCOL *This,
306 OUT BOOLEAN *State
307 )
308 {
309 CPU_ARCH_PROTOCOL_PRIVATE *Private;
310
311 if (State == NULL) {
312 return EFI_INVALID_PARAMETER;
313 }
314
315 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
316 *State = Private->InterruptState;
317 return EFI_SUCCESS;
318 }
319
320 EFI_STATUS
321 EFIAPI
322 EmuInit (
323 IN EFI_CPU_ARCH_PROTOCOL *This,
324 IN EFI_CPU_INIT_TYPE InitType
325 )
326 {
327 return EFI_UNSUPPORTED;
328 }
329
330 EFI_STATUS
331 EFIAPI
332 EmuRegisterInterruptHandler (
333 IN EFI_CPU_ARCH_PROTOCOL *This,
334 IN EFI_EXCEPTION_TYPE InterruptType,
335 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
336 )
337 {
338 //
339 // Do parameter checking for EFI spec conformance
340 //
341 if (InterruptType < 0 || InterruptType > 0xff) {
342 return EFI_UNSUPPORTED;
343 }
344 //
345 // Do nothing for Emu emulation
346 //
347 return EFI_UNSUPPORTED;
348 }
349
350 EFI_STATUS
351 EFIAPI
352 EmuGetTimerValue (
353 IN EFI_CPU_ARCH_PROTOCOL *This,
354 IN UINT32 TimerIndex,
355 OUT UINT64 *TimerValue,
356 OUT UINT64 *TimerPeriod OPTIONAL
357 )
358 {
359 if (TimerValue == NULL) {
360 return EFI_INVALID_PARAMETER;
361 }
362
363 if (TimerIndex != 0) {
364 return EFI_INVALID_PARAMETER;
365 }
366
367 *TimerValue = gEmuThunk->QueryPerformanceCounter ();
368
369 if (TimerPeriod != NULL) {
370 *TimerPeriod = mTimerPeriod;
371 }
372
373 return EFI_SUCCESS;
374 }
375
376
377 EFI_STATUS
378 EFIAPI
379 EmuSetMemoryAttributes (
380 IN EFI_CPU_ARCH_PROTOCOL *This,
381 IN EFI_PHYSICAL_ADDRESS BaseAddress,
382 IN UINT64 Length,
383 IN UINT64 Attributes
384 )
385 {
386 //
387 // Check for invalid parameter for Spec conformance
388 //
389 if (Length == 0) {
390 return EFI_INVALID_PARAMETER;
391 }
392
393 //
394 // Do nothing for Nt32 emulation
395 //
396 return EFI_UNSUPPORTED;
397 }
398
399
400
401
402 /**
403 Callback function for idle events.
404
405 @param Event Event whose notification function is being invoked.
406 @param Context The pointer to the notification function's context,
407 which is implementation-dependent.
408
409 **/
410 VOID
411 EFIAPI
412 IdleLoopEventCallback (
413 IN EFI_EVENT Event,
414 IN VOID *Context
415 )
416 {
417 gEmuThunk->CpuSleep ();
418 }
419
420
421 EFI_STATUS
422 EFIAPI
423 InitializeCpu (
424 IN EFI_HANDLE ImageHandle,
425 IN EFI_SYSTEM_TABLE *SystemTable
426 )
427 {
428 EFI_STATUS Status;
429 UINT64 Frequency;
430 EFI_EVENT IdleLoopEvent;
431 UINTN MaxCpu;
432
433 //
434 // Retrieve the frequency of the performance counter in Hz.
435 //
436 Frequency = gEmuThunk->QueryPerformanceFrequency ();
437
438 //
439 // Convert frequency in Hz to a clock period in femtoseconds.
440 //
441 mTimerPeriod = DivU64x64Remainder (1000000000000000ULL, Frequency, NULL);
442
443 CpuMpServicesInit (&MaxCpu);
444
445 CpuUpdateSmbios (MaxCpu);
446
447
448 Status = gBS->CreateEventEx (
449 EVT_NOTIFY_SIGNAL,
450 TPL_NOTIFY,
451 IdleLoopEventCallback,
452 NULL,
453 &gIdleLoopEventGuid,
454 &IdleLoopEvent
455 );
456 ASSERT_EFI_ERROR (Status);
457
458
459 Status = gBS->InstallMultipleProtocolInterfaces (
460 &mCpuTemplate.Handle,
461 &gEfiCpuArchProtocolGuid, &mCpuTemplate.Cpu,
462 &gEfiCpuIo2ProtocolGuid, &mCpuTemplate.CpuIo,
463 NULL
464 );
465 ASSERT_EFI_ERROR (Status);
466
467 return Status;
468 }