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