]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/CpuRuntimeDxe/Cpu.c
EmulatorPkg: Replace BSD License with BSD+Patent License
[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 LogSmbiosData ((EFI_SMBIOS_TABLE_HEADER *)&mCpuSmbiosType4, mCpuSmbiosType4Strings);
243 }
244
245
246 //
247 // Service routines for the driver
248 //
249 EFI_STATUS
250 EFIAPI
251 EmuFlushCpuDataCache (
252 IN EFI_CPU_ARCH_PROTOCOL *This,
253 IN EFI_PHYSICAL_ADDRESS Start,
254 IN UINT64 Length,
255 IN EFI_CPU_FLUSH_TYPE FlushType
256 )
257 {
258 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
259 //
260 // Only WB flush is supported. We actually need do nothing on Emu emulator
261 // environment. Classify this to follow EFI spec
262 //
263 return EFI_SUCCESS;
264 }
265 //
266 // Other flush types are not supported by Emu emulator
267 //
268 return EFI_UNSUPPORTED;
269 }
270
271 EFI_STATUS
272 EFIAPI
273 EmuEnableInterrupt (
274 IN EFI_CPU_ARCH_PROTOCOL *This
275 )
276 {
277 CPU_ARCH_PROTOCOL_PRIVATE *Private;
278
279 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
280 Private->InterruptState = TRUE;
281 gEmuThunk->EnableInterrupt ();
282 return EFI_SUCCESS;
283 }
284
285 EFI_STATUS
286 EFIAPI
287 EmuDisableInterrupt (
288 IN EFI_CPU_ARCH_PROTOCOL *This
289 )
290 {
291 CPU_ARCH_PROTOCOL_PRIVATE *Private;
292
293 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
294 Private->InterruptState = FALSE;
295 gEmuThunk->DisableInterrupt ();
296 return EFI_SUCCESS;
297 }
298
299 EFI_STATUS
300 EFIAPI
301 EmuGetInterruptState (
302 IN EFI_CPU_ARCH_PROTOCOL *This,
303 OUT BOOLEAN *State
304 )
305 {
306 CPU_ARCH_PROTOCOL_PRIVATE *Private;
307
308 if (State == NULL) {
309 return EFI_INVALID_PARAMETER;
310 }
311
312 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);
313 *State = Private->InterruptState;
314 return EFI_SUCCESS;
315 }
316
317 EFI_STATUS
318 EFIAPI
319 EmuInit (
320 IN EFI_CPU_ARCH_PROTOCOL *This,
321 IN EFI_CPU_INIT_TYPE InitType
322 )
323 {
324 return EFI_UNSUPPORTED;
325 }
326
327 EFI_STATUS
328 EFIAPI
329 EmuRegisterInterruptHandler (
330 IN EFI_CPU_ARCH_PROTOCOL *This,
331 IN EFI_EXCEPTION_TYPE InterruptType,
332 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
333 )
334 {
335 //
336 // Do parameter checking for EFI spec conformance
337 //
338 if (InterruptType < 0 || InterruptType > 0xff) {
339 return EFI_UNSUPPORTED;
340 }
341 //
342 // Do nothing for Emu emulation
343 //
344 return EFI_UNSUPPORTED;
345 }
346
347 EFI_STATUS
348 EFIAPI
349 EmuGetTimerValue (
350 IN EFI_CPU_ARCH_PROTOCOL *This,
351 IN UINT32 TimerIndex,
352 OUT UINT64 *TimerValue,
353 OUT UINT64 *TimerPeriod OPTIONAL
354 )
355 {
356 if (TimerValue == NULL) {
357 return EFI_INVALID_PARAMETER;
358 }
359
360 if (TimerIndex != 0) {
361 return EFI_INVALID_PARAMETER;
362 }
363
364 *TimerValue = gEmuThunk->QueryPerformanceCounter ();
365
366 if (TimerPeriod != NULL) {
367 *TimerPeriod = mTimerPeriod;
368 }
369
370 return EFI_SUCCESS;
371 }
372
373
374 EFI_STATUS
375 EFIAPI
376 EmuSetMemoryAttributes (
377 IN EFI_CPU_ARCH_PROTOCOL *This,
378 IN EFI_PHYSICAL_ADDRESS BaseAddress,
379 IN UINT64 Length,
380 IN UINT64 Attributes
381 )
382 {
383 //
384 // Check for invalid parameter for Spec conformance
385 //
386 if (Length == 0) {
387 return EFI_INVALID_PARAMETER;
388 }
389
390 //
391 // Do nothing for Nt32 emulation
392 //
393 return EFI_UNSUPPORTED;
394 }
395
396
397
398
399 /**
400 Callback function for idle events.
401
402 @param Event Event whose notification function is being invoked.
403 @param Context The pointer to the notification function's context,
404 which is implementation-dependent.
405
406 **/
407 VOID
408 EFIAPI
409 IdleLoopEventCallback (
410 IN EFI_EVENT Event,
411 IN VOID *Context
412 )
413 {
414 gEmuThunk->CpuSleep ();
415 }
416
417
418 EFI_STATUS
419 EFIAPI
420 InitializeCpu (
421 IN EFI_HANDLE ImageHandle,
422 IN EFI_SYSTEM_TABLE *SystemTable
423 )
424 {
425 EFI_STATUS Status;
426 UINT64 Frequency;
427 EFI_EVENT IdleLoopEvent;
428 UINTN MaxCpu;
429
430 //
431 // Retrieve the frequency of the performance counter in Hz.
432 //
433 Frequency = gEmuThunk->QueryPerformanceFrequency ();
434
435 //
436 // Convert frequency in Hz to a clock period in femtoseconds.
437 //
438 mTimerPeriod = DivU64x64Remainder (1000000000000000ULL, Frequency, NULL);
439
440 CpuMpServicesInit (&MaxCpu);
441
442 CpuUpdateSmbios (MaxCpu);
443
444
445 Status = gBS->CreateEventEx (
446 EVT_NOTIFY_SIGNAL,
447 TPL_NOTIFY,
448 IdleLoopEventCallback,
449 NULL,
450 &gIdleLoopEventGuid,
451 &IdleLoopEvent
452 );
453 ASSERT_EFI_ERROR (Status);
454
455
456 Status = gBS->InstallMultipleProtocolInterfaces (
457 &mCpuTemplate.Handle,
458 &gEfiCpuArchProtocolGuid, &mCpuTemplate.Cpu,
459 &gEfiCpuIo2ProtocolGuid, &mCpuTemplate.CpuIo,
460 NULL
461 );
462 ASSERT_EFI_ERROR (Status);
463
464 return Status;
465 }