]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/CpuRuntimeDxe/Cpu.c
According to PI errata 0000654 and 000811, we need use 0xFFFE to instead of 0 for...
[mirror_edk2.git] / EmulatorPkg / CpuRuntimeDxe / Cpu.c
CommitLineData
949f388f 1/*++ @file\r
2 Emu driver to produce CPU Architectural Protocol.\r
d18d8a1d 3\r
949f388f 4Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
5Portions copyright (c) 2011, Apple Inc. All rights reserved.\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "CpuDriver.h"\r
17\r
18UINT64 mTimerPeriod;\r
19\r
20CPU_ARCH_PROTOCOL_PRIVATE mCpuTemplate = {\r
21 CPU_ARCH_PROT_PRIVATE_SIGNATURE,\r
22 NULL,\r
23 {\r
24 EmuFlushCpuDataCache,\r
25 EmuEnableInterrupt,\r
26 EmuDisableInterrupt,\r
27 EmuGetInterruptState,\r
28 EmuInit,\r
29 EmuRegisterInterruptHandler,\r
30 EmuGetTimerValue,\r
31 EmuSetMemoryAttributes,\r
32 0,\r
33 4\r
34 },\r
35 {\r
36 {\r
37 CpuMemoryServiceRead,\r
38 CpuMemoryServiceWrite\r
39 },\r
40 {\r
41 CpuIoServiceRead,\r
42 CpuIoServiceWrite\r
43 }\r
44 },\r
45 TRUE\r
46};\r
47\r
48#define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100\r
49\r
50\r
51\r
52//\r
53// Service routines for the driver\r
54//\r
55EFI_STATUS\r
56EFIAPI\r
57EmuFlushCpuDataCache (\r
58 IN EFI_CPU_ARCH_PROTOCOL *This,\r
59 IN EFI_PHYSICAL_ADDRESS Start,\r
60 IN UINT64 Length,\r
61 IN EFI_CPU_FLUSH_TYPE FlushType\r
62 )\r
63{\r
64 if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {\r
65 //\r
66 // Only WB flush is supported. We actually need do nothing on Emu emulator\r
67 // environment. Classify this to follow EFI spec\r
68 //\r
69 return EFI_SUCCESS;\r
70 }\r
71 //\r
72 // Other flush types are not supported by Emu emulator\r
73 //\r
74 return EFI_UNSUPPORTED;\r
75}\r
76\r
77EFI_STATUS\r
78EFIAPI\r
79EmuEnableInterrupt (\r
80 IN EFI_CPU_ARCH_PROTOCOL *This\r
81 )\r
82{\r
83 CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
84\r
85 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);\r
86 Private->InterruptState = TRUE;\r
87 gEmuThunk->EnableInterrupt ();\r
88 return EFI_SUCCESS;\r
89}\r
90\r
91EFI_STATUS\r
92EFIAPI\r
93EmuDisableInterrupt (\r
94 IN EFI_CPU_ARCH_PROTOCOL *This\r
95 )\r
96{\r
97 CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
98\r
99 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);\r
100 Private->InterruptState = FALSE;\r
101 gEmuThunk->DisableInterrupt ();\r
102 return EFI_SUCCESS;\r
103}\r
104\r
105EFI_STATUS\r
106EFIAPI\r
107EmuGetInterruptState (\r
108 IN EFI_CPU_ARCH_PROTOCOL *This,\r
109 OUT BOOLEAN *State\r
110 )\r
111{\r
112 CPU_ARCH_PROTOCOL_PRIVATE *Private;\r
113\r
114 if (State == NULL) {\r
115 return EFI_INVALID_PARAMETER;\r
116 }\r
117\r
118 Private = CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS (This);\r
119 *State = Private->InterruptState;\r
120 return EFI_SUCCESS;\r
121}\r
122\r
123EFI_STATUS\r
124EFIAPI\r
125EmuInit (\r
126 IN EFI_CPU_ARCH_PROTOCOL *This,\r
127 IN EFI_CPU_INIT_TYPE InitType\r
128 )\r
129{\r
949f388f 130 return EFI_UNSUPPORTED;\r
131}\r
132\r
133EFI_STATUS\r
134EFIAPI\r
135EmuRegisterInterruptHandler (\r
136 IN EFI_CPU_ARCH_PROTOCOL *This,\r
137 IN EFI_EXCEPTION_TYPE InterruptType,\r
138 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
139 )\r
140{\r
949f388f 141 //\r
142 // Do parameter checking for EFI spec conformance\r
143 //\r
144 if (InterruptType < 0 || InterruptType > 0xff) {\r
145 return EFI_UNSUPPORTED;\r
146 }\r
147 //\r
148 // Do nothing for Emu emulation\r
149 //\r
949f388f 150 return EFI_UNSUPPORTED;\r
151}\r
152\r
153EFI_STATUS\r
154EFIAPI\r
155EmuGetTimerValue (\r
156 IN EFI_CPU_ARCH_PROTOCOL *This,\r
157 IN UINT32 TimerIndex,\r
158 OUT UINT64 *TimerValue,\r
159 OUT UINT64 *TimerPeriod OPTIONAL\r
160 )\r
161{\r
162 if (TimerValue == NULL) {\r
163 return EFI_INVALID_PARAMETER;\r
164 }\r
165\r
166 if (TimerIndex != 0) {\r
167 return EFI_INVALID_PARAMETER;\r
168 }\r
d18d8a1d 169\r
949f388f 170 *TimerValue = gEmuThunk->QueryPerformanceCounter ();\r
d18d8a1d 171\r
949f388f 172 if (TimerPeriod != NULL) {\r
173 *TimerPeriod = mTimerPeriod;\r
d18d8a1d 174 }\r
949f388f 175\r
176 return EFI_SUCCESS;\r
177}\r
178\r
179\r
180EFI_STATUS\r
181EFIAPI\r
182EmuSetMemoryAttributes (\r
183 IN EFI_CPU_ARCH_PROTOCOL *This,\r
184 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
185 IN UINT64 Length,\r
186 IN UINT64 Attributes\r
187 )\r
188{\r
949f388f 189 //\r
190 // Check for invalid parameter for Spec conformance\r
191 //\r
192 if (Length == 0) {\r
193 return EFI_INVALID_PARAMETER;\r
194 }\r
195\r
196 //\r
197 // Do nothing for Nt32 emulation\r
198 //\r
949f388f 199 return EFI_UNSUPPORTED;\r
200}\r
201\r
202\r
203\r
204/**\r
205 Logs SMBIOS record.\r
206\r
207 @param Smbios Pointer to SMBIOS protocol instance.\r
208 @param Buffer Pointer to the data buffer.\r
209\r
210**/\r
211VOID\r
212LogSmbiosData (\r
213 IN EFI_SMBIOS_PROTOCOL *Smbios,\r
214 IN UINT8 *Buffer\r
215 )\r
216{\r
217 EFI_STATUS Status;\r
218 EFI_SMBIOS_HANDLE SmbiosHandle;\r
d18d8a1d 219\r
2bfd90f9 220 SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;\r
949f388f 221 Status = Smbios->Add (\r
222 Smbios,\r
223 NULL,\r
224 &SmbiosHandle,\r
225 (EFI_SMBIOS_TABLE_HEADER*)Buffer\r
226 );\r
227 ASSERT_EFI_ERROR (Status);\r
228}\r
229\r
230VOID\r
231CpuUpdateSmbios (\r
232 VOID\r
233 )\r
234{\r
235 EFI_STATUS Status;\r
236 UINT32 TotalSize;\r
237 EFI_SMBIOS_PROTOCOL *Smbios;\r
238 EFI_HII_HANDLE HiiHandle;\r
239 STRING_REF Token;\r
240 UINTN CpuVerStrLen;\r
241 EFI_STRING CpuVerStr;\r
242 SMBIOS_TABLE_TYPE4 *SmbiosRecord;\r
243 CHAR8 *OptionalStrStart;\r
244\r
245 //\r
246 // Locate Smbios protocol.\r
247 //\r
248 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&Smbios);\r
d18d8a1d 249\r
949f388f 250 if (EFI_ERROR (Status)) {\r
251 return;\r
252 }\r
253\r
254 //\r
255 // Initialize strings to HII database\r
256 //\r
257 HiiHandle = HiiAddPackages (\r
258 &gEfiCallerIdGuid,\r
259 NULL,\r
260 CpuStrings,\r
261 NULL\r
262 );\r
263 ASSERT (HiiHandle != NULL);\r
264\r
265 Token = STRING_TOKEN (STR_PROCESSOR_VERSION);\r
266 CpuVerStr = HiiGetPackageString(&gEfiCallerIdGuid, Token, NULL);\r
267 CpuVerStrLen = StrLen(CpuVerStr);\r
268 ASSERT (CpuVerStrLen <= SMBIOS_STRING_MAX_LENGTH);\r
269\r
270 TotalSize = sizeof(SMBIOS_TABLE_TYPE4) + CpuVerStrLen + 1 + 1;\r
271 SmbiosRecord = AllocatePool(TotalSize);\r
272 ZeroMem(SmbiosRecord, TotalSize);\r
273\r
274 SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION;\r
275 SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4);\r
276 //\r
277 // Make handle chosen by smbios protocol.add automatically.\r
278 //\r
d18d8a1d 279 SmbiosRecord->Hdr.Handle = 0;\r
949f388f 280 //\r
281 // Processor version is the 1st string.\r
282 //\r
283 SmbiosRecord->ProcessorVersion = 1;\r
284 //\r
285 // Store CPU frequency data record to data hub - It's an emulator so make up a value\r
286 //\r
287 SmbiosRecord->CurrentSpeed = 1234;\r
288\r
289 OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1);\r
290 UnicodeStrToAsciiStr(CpuVerStr, OptionalStrStart);\r
291\r
292 //\r
293 // Now we have got the full smbios record, call smbios protocol to add this record.\r
294 //\r
295 LogSmbiosData(Smbios, (UINT8 *) SmbiosRecord);\r
296 FreePool (SmbiosRecord);\r
297}\r
298\r
57c7d70f 299\r
300\r
301/**\r
302 Callback function for idle events.\r
d18d8a1d 303\r
57c7d70f 304 @param Event Event whose notification function is being invoked.\r
305 @param Context The pointer to the notification function's context,\r
306 which is implementation-dependent.\r
307\r
308**/\r
309VOID\r
310EFIAPI\r
311IdleLoopEventCallback (\r
312 IN EFI_EVENT Event,\r
313 IN VOID *Context\r
314 )\r
315{\r
316 gEmuThunk->CpuSleep ();\r
317}\r
318\r
319\r
949f388f 320EFI_STATUS\r
321EFIAPI\r
322InitializeCpu (\r
323 IN EFI_HANDLE ImageHandle,\r
324 IN EFI_SYSTEM_TABLE *SystemTable\r
325 )\r
326{\r
327 EFI_STATUS Status;\r
328 UINT64 Frequency;\r
57c7d70f 329 EFI_EVENT IdleLoopEvent;\r
949f388f 330\r
331 //\r
332 // Retrieve the frequency of the performance counter in Hz.\r
d18d8a1d 333 //\r
949f388f 334 Frequency = gEmuThunk->QueryPerformanceFrequency ();\r
d18d8a1d 335\r
949f388f 336 //\r
337 // Convert frequency in Hz to a clock period in femtoseconds.\r
338 //\r
7e284acb 339 mTimerPeriod = DivU64x64Remainder (1000000000000000ULL, Frequency, NULL);\r
949f388f 340\r
341 CpuUpdateSmbios ();\r
d18d8a1d 342\r
c4671a67 343 CpuMpServicesInit ();\r
d18d8a1d 344\r
57c7d70f 345 Status = gBS->CreateEventEx (\r
346 EVT_NOTIFY_SIGNAL,\r
347 TPL_NOTIFY,\r
348 IdleLoopEventCallback,\r
349 NULL,\r
350 &gIdleLoopEventGuid,\r
351 &IdleLoopEvent\r
352 );\r
353 ASSERT_EFI_ERROR (Status);\r
354\r
949f388f 355\r
356 Status = gBS->InstallMultipleProtocolInterfaces (\r
357 &mCpuTemplate.Handle,\r
358 &gEfiCpuArchProtocolGuid, &mCpuTemplate.Cpu,\r
359 &gEfiCpuIo2ProtocolGuid, &mCpuTemplate.CpuIo,\r
360 NULL\r
361 );\r
362 ASSERT_EFI_ERROR (Status);\r
363\r
364 return Status;\r
365}\r