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