]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/CpuRuntimeDxe/Cpu.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 Create SMBIOS record.
134
135 Converts a fixed SMBIOS structure and an array of pointers to strings into
136 an SMBIOS record where the strings are cat'ed on the end of the fixed record
137 and terminated via a double NULL and add to SMBIOS table.
138
139 SMBIOS_TABLE_TYPE32 gSmbiosType12 = {
140 { EFI_SMBIOS_TYPE_SYSTEM_CONFIGURATION_OPTIONS, sizeof (SMBIOS_TABLE_TYPE12), 0 },
141 1 // StringCount
142 };
143 CHAR8 *gSmbiosType12Strings[] = {
144 "Not Found",
145 NULL
146 };
147
148 ...
149 LogSmbiosData (
150 (EFI_SMBIOS_TABLE_HEADER*)&gSmbiosType12,
151 gSmbiosType12Strings
152 );
153
154 @param Template Fixed SMBIOS structure, required.
155 @param StringArray Array of strings to convert to an SMBIOS string pack.
156 NULL is OK.
157
158 **/
159 EFI_STATUS
160 LogSmbiosData (
161 IN EFI_SMBIOS_TABLE_HEADER *Template,
162 IN CHAR8 **StringPack
163 )
164 {
165 EFI_STATUS Status;
166 EFI_SMBIOS_PROTOCOL *Smbios;
167 EFI_SMBIOS_HANDLE SmbiosHandle;
168 EFI_SMBIOS_TABLE_HEADER *Record;
169 UINTN Index;
170 UINTN StringSize;
171 UINTN Size;
172 CHAR8 *Str;
173
174 //
175 // Locate Smbios protocol.
176 //
177 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios);
178 if (EFI_ERROR (Status)) {
179 return Status;
180 }
181
182 // Calculate the size of the fixed record and optional string pack
183 Size = Template->Length;
184 if (StringPack == NULL) {
185 // At least a double null is required
186 Size += 2;
187 } else {
188 for (Index = 0; StringPack[Index] != NULL; Index++) {
189 StringSize = AsciiStrSize (StringPack[Index]);
190 Size += StringSize;
191 }
192
193 if (StringPack[0] == NULL) {
194 // At least a double null is required
195 Size += 1;
196 }
197
198 // Don't forget the terminating double null
199 Size += 1;
200 }
201
202 // Copy over Template
203 Record = (EFI_SMBIOS_TABLE_HEADER *)AllocateZeroPool (Size);
204 if (Record == NULL) {
205 return EFI_OUT_OF_RESOURCES;
206 }
207
208 CopyMem (Record, Template, Template->Length);
209
210 // Append string pack
211 Str = ((CHAR8 *)Record) + Record->Length;
212 for (Index = 0; StringPack[Index] != NULL; Index++) {
213 StringSize = AsciiStrSize (StringPack[Index]);
214 CopyMem (Str, StringPack[Index], StringSize);
215 Str += StringSize;
216 }
217
218 *Str = 0;
219
220 SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
221 Status = Smbios->Add (
222 Smbios,
223 gImageHandle,
224 &SmbiosHandle,
225 Record
226 );
227 ASSERT_EFI_ERROR (Status);
228
229 FreePool (Record);
230 return Status;
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 // Service routines for the driver
250 //
251 EFI_STATUS
252 EFIAPI
253 EmuFlushCpuDataCache (
254 IN EFI_CPU_ARCH_PROTOCOL *This,
255 IN EFI_PHYSICAL_ADDRESS Start,
256 IN UINT64 Length,
257 IN EFI_CPU_FLUSH_TYPE FlushType
258 )
259 {
260 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
261 //
262 // Only WB flush is supported. We actually need do nothing on Emu emulator
263 // environment. Classify this to follow EFI spec
264 //
265 return EFI_SUCCESS;
266 }
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 //
346 // Do nothing for Emu emulation
347 //
348 return EFI_UNSUPPORTED;
349 }
350
351 EFI_STATUS
352 EFIAPI
353 EmuGetTimerValue (
354 IN EFI_CPU_ARCH_PROTOCOL *This,
355 IN UINT32 TimerIndex,
356 OUT UINT64 *TimerValue,
357 OUT UINT64 *TimerPeriod OPTIONAL
358 )
359 {
360 if (TimerValue == NULL) {
361 return EFI_INVALID_PARAMETER;
362 }
363
364 if (TimerIndex != 0) {
365 return EFI_INVALID_PARAMETER;
366 }
367
368 *TimerValue = gEmuThunk->QueryPerformanceCounter ();
369
370 if (TimerPeriod != NULL) {
371 *TimerPeriod = mTimerPeriod;
372 }
373
374 return EFI_SUCCESS;
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 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 EFI_STATUS
418 EFIAPI
419 InitializeCpu (
420 IN EFI_HANDLE ImageHandle,
421 IN EFI_SYSTEM_TABLE *SystemTable
422 )
423 {
424 EFI_STATUS Status;
425 UINT64 Frequency;
426 EFI_EVENT IdleLoopEvent;
427 UINTN MaxCpu;
428
429 //
430 // Retrieve the frequency of the performance counter in Hz.
431 //
432 Frequency = gEmuThunk->QueryPerformanceFrequency ();
433
434 //
435 // Convert frequency in Hz to a clock period in femtoseconds.
436 //
437 mTimerPeriod = DivU64x64Remainder (1000000000000000ULL, Frequency, NULL);
438
439 CpuMpServicesInit (&MaxCpu);
440
441 CpuUpdateSmbios (MaxCpu);
442
443 Status = gBS->CreateEventEx (
444 EVT_NOTIFY_SIGNAL,
445 TPL_NOTIFY,
446 IdleLoopEventCallback,
447 NULL,
448 &gIdleLoopEventGuid,
449 &IdleLoopEvent
450 );
451 ASSERT_EFI_ERROR (Status);
452
453 Status = gBS->InstallMultipleProtocolInterfaces (
454 &mCpuTemplate.Handle,
455 &gEfiCpuArchProtocolGuid,
456 &mCpuTemplate.Cpu,
457 &gEfiCpuIo2ProtocolGuid,
458 &mCpuTemplate.CpuIo,
459 NULL
460 );
461 ASSERT_EFI_ERROR (Status);
462
463 return Status;
464 }