]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c
Make EdkModulePkg pass Intel IPF compiler with /W4 /WX switches, solving warning...
[mirror_edk2.git] / EdkModulePkg / Universal / Ebc / Dxe / EbcInt.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name: \r
13\r
14 EbcInt.c\r
15 \r
16Abstract:\r
17\r
18 Top level module for the EBC virtual machine implementation.\r
19 Provides auxilliary support routines for the VM. That is, routines\r
20 that are not particularly related to VM execution of EBC instructions.\r
21 \r
22--*/\r
23\r
24#include "EbcInt.h"\r
25#include "EbcExecute.h"\r
26\r
27//\r
28// We'll keep track of all thunks we create in a linked list. Each\r
29// thunk is tied to an image handle, so we have a linked list of\r
30// image handles, with each having a linked list of thunks allocated\r
31// to that image handle.\r
32//\r
33typedef struct _EBC_THUNK_LIST {\r
34 VOID *ThunkBuffer;\r
35 struct _EBC_THUNK_LIST *Next;\r
36} EBC_THUNK_LIST;\r
37\r
38typedef struct _EBC_IMAGE_LIST {\r
39 struct _EBC_IMAGE_LIST *Next;\r
40 EFI_HANDLE ImageHandle;\r
41 EBC_THUNK_LIST *ThunkList;\r
42} EBC_IMAGE_LIST;\r
43\r
878ddf1f 44STATIC\r
45EFI_STATUS\r
46EFIAPI\r
47EbcUnloadImage (\r
48 IN EFI_EBC_PROTOCOL *This,\r
49 IN EFI_HANDLE ImageHandle\r
50 );\r
51\r
52STATIC\r
53EFI_STATUS\r
54EFIAPI\r
55EbcCreateThunk (\r
56 IN EFI_EBC_PROTOCOL *This,\r
57 IN EFI_HANDLE ImageHandle,\r
58 IN VOID *EbcEntryPoint,\r
59 OUT VOID **Thunk\r
60 );\r
61\r
62STATIC\r
63EFI_STATUS\r
64EFIAPI\r
65EbcGetVersion (\r
66 IN EFI_EBC_PROTOCOL *This,\r
67 IN OUT UINT64 *Version\r
68 );\r
69\r
92dda53e 70STATIC\r
c91eaa3d 71EFI_STATUS\r
72EFIAPI\r
73InitializeEbcCallback (\r
74 IN EFI_DEBUG_SUPPORT_PROTOCOL *This\r
75 );\r
76\r
92dda53e 77STATIC\r
c91eaa3d 78VOID\r
79EFIAPI\r
80CommonEbcExceptionHandler (\r
81 IN EFI_EXCEPTION_TYPE InterruptType,\r
82 IN EFI_SYSTEM_CONTEXT SystemContext\r
83 );\r
84\r
92dda53e 85STATIC\r
c91eaa3d 86VOID\r
87EFIAPI\r
88EbcPeriodicNotifyFunction (\r
89 IN EFI_EVENT Event,\r
90 IN VOID *Context\r
91 );\r
92\r
92dda53e 93STATIC\r
c91eaa3d 94EFI_STATUS\r
95EFIAPI\r
96EbcDebugPeriodic (\r
97 IN VM_CONTEXT *VmPtr\r
98 );\r
99\r
878ddf1f 100//\r
101// These two functions and the GUID are used to produce an EBC test protocol.\r
102// This functionality is definitely not required for execution.\r
103//\r
104STATIC\r
105EFI_STATUS\r
106InitEbcVmTestProtocol (\r
107 IN EFI_HANDLE *Handle\r
108 );\r
109\r
110STATIC\r
111EFI_STATUS\r
112EbcVmTestUnsupported (\r
113 VOID\r
114 );\r
115\r
116STATIC\r
117EFI_STATUS\r
118EFIAPI\r
119EbcRegisterICacheFlush (\r
120 IN EFI_EBC_PROTOCOL *This,\r
121 IN EBC_ICACHE_FLUSH Flush\r
122 );\r
123\r
124STATIC\r
125EFI_STATUS\r
126EFIAPI\r
127EbcDebugGetMaximumProcessorIndex (\r
128 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
129 OUT UINTN *MaxProcessorIndex\r
130 );\r
131\r
132STATIC\r
133EFI_STATUS\r
134EFIAPI\r
135EbcDebugRegisterPeriodicCallback (\r
136 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
137 IN UINTN ProcessorIndex,\r
138 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
139 );\r
140\r
141STATIC\r
142EFI_STATUS\r
143EFIAPI\r
144EbcDebugRegisterExceptionCallback (\r
145 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
146 IN UINTN ProcessorIndex,\r
147 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,\r
148 IN EFI_EXCEPTION_TYPE ExceptionType\r
149 );\r
150\r
151STATIC\r
152EFI_STATUS\r
153EFIAPI\r
154EbcDebugInvalidateInstructionCache (\r
155 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
156 IN UINTN ProcessorIndex,\r
157 IN VOID *Start,\r
158 IN UINT64 Length\r
159 );\r
160\r
161//\r
162// We have one linked list of image handles for the whole world. Since\r
163// there should only be one interpreter, make them global. They must\r
164// also be global since the execution of an EBC image does not provide\r
165// a This pointer.\r
166//\r
167static EBC_IMAGE_LIST *mEbcImageList = NULL;\r
168\r
169//\r
170// Callback function to flush the icache after thunk creation\r
171//\r
172static EBC_ICACHE_FLUSH mEbcICacheFlush;\r
173\r
174//\r
175// These get set via calls by the debug agent\r
176//\r
3114b334 177static EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;\r
178static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};\r
878ddf1f 179static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;\r
180\r
c91eaa3d 181//\r
182// Event for Periodic callback\r
183//\r
184static EFI_EVENT mEbcPeriodicEvent;\r
185VM_CONTEXT *mVmPtr = NULL;\r
186\r
878ddf1f 187EFI_STATUS\r
188EFIAPI\r
189InitializeEbcDriver (\r
190 IN EFI_HANDLE ImageHandle,\r
191 IN EFI_SYSTEM_TABLE *SystemTable\r
192 )\r
193/*++\r
194\r
195Routine Description: \r
196\r
197 Initializes the VM EFI interface. Allocates memory for the VM interface \r
198 and registers the VM protocol.\r
199\r
200Arguments: \r
201\r
202 ImageHandle - EFI image handle.\r
203 SystemTable - Pointer to the EFI system table.\r
204\r
205Returns: \r
206 Standard EFI status code.\r
207\r
208--*/\r
209{\r
210 EFI_EBC_PROTOCOL *EbcProtocol;\r
211 EFI_EBC_PROTOCOL *OldEbcProtocol;\r
212 EFI_STATUS Status;\r
213 EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;\r
214 EFI_HANDLE *HandleBuffer;\r
215 UINTN NumHandles;\r
216 UINTN Index;\r
217 BOOLEAN Installed;\r
218\r
c91eaa3d 219 EbcProtocol = NULL;\r
220 EbcDebugProtocol = NULL;\r
221\r
878ddf1f 222 //\r
223 // Allocate memory for our protocol. Then fill in the blanks.\r
224 //\r
225 Status = gBS->AllocatePool (\r
226 EfiBootServicesData,\r
227 sizeof (EFI_EBC_PROTOCOL),\r
228 (VOID **) &EbcProtocol\r
229 );\r
230 if (Status != EFI_SUCCESS) {\r
231 return EFI_OUT_OF_RESOURCES;\r
232 }\r
233\r
234 EbcProtocol->CreateThunk = EbcCreateThunk;\r
235 EbcProtocol->UnloadImage = EbcUnloadImage;\r
236 EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;\r
237 EbcProtocol->GetVersion = EbcGetVersion;\r
238 mEbcICacheFlush = NULL;\r
239\r
240 //\r
241 // Find any already-installed EBC protocols and uninstall them\r
242 //\r
243 Installed = FALSE;\r
244 HandleBuffer = NULL;\r
245 Status = gBS->LocateHandleBuffer (\r
246 ByProtocol,\r
247 &gEfiEbcProtocolGuid,\r
248 NULL,\r
249 &NumHandles,\r
250 &HandleBuffer\r
251 );\r
252 if (Status == EFI_SUCCESS) {\r
253 //\r
254 // Loop through the handles\r
255 //\r
256 for (Index = 0; Index < NumHandles; Index++) {\r
257 Status = gBS->HandleProtocol (\r
258 HandleBuffer[Index],\r
259 &gEfiEbcProtocolGuid,\r
260 (VOID **) &OldEbcProtocol\r
261 );\r
262 if (Status == EFI_SUCCESS) {\r
263 if (gBS->ReinstallProtocolInterface (\r
264 HandleBuffer[Index],\r
265 &gEfiEbcProtocolGuid,\r
266 OldEbcProtocol,\r
267 EbcProtocol\r
268 ) == EFI_SUCCESS) {\r
269 Installed = TRUE;\r
270 }\r
271 }\r
272 }\r
273 }\r
274\r
275 if (HandleBuffer != NULL) {\r
276 gBS->FreePool (HandleBuffer);\r
277 HandleBuffer = NULL;\r
278 }\r
279 //\r
280 // Add the protocol so someone can locate us if we haven't already.\r
281 //\r
282 if (!Installed) {\r
283 Status = gBS->InstallProtocolInterface (\r
284 &ImageHandle,\r
285 &gEfiEbcProtocolGuid,\r
286 EFI_NATIVE_INTERFACE,\r
287 EbcProtocol\r
288 );\r
289 if (EFI_ERROR (Status)) {\r
290 gBS->FreePool (EbcProtocol);\r
291 return Status;\r
292 }\r
293 }\r
294 //\r
295 // Allocate memory for our debug protocol. Then fill in the blanks.\r
296 //\r
297 Status = gBS->AllocatePool (\r
298 EfiBootServicesData,\r
299 sizeof (EFI_DEBUG_SUPPORT_PROTOCOL),\r
300 (VOID **) &EbcDebugProtocol\r
301 );\r
302 if (Status != EFI_SUCCESS) {\r
c91eaa3d 303 goto ErrorExit;\r
878ddf1f 304 }\r
305\r
306 EbcDebugProtocol->Isa = IsaEbc;\r
307 EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;\r
308 EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;\r
309 EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;\r
310 EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;\r
311\r
312 //\r
313 // Add the protocol so the debug agent can find us\r
314 //\r
315 Status = gBS->InstallProtocolInterface (\r
316 &ImageHandle,\r
317 &gEfiDebugSupportProtocolGuid,\r
318 EFI_NATIVE_INTERFACE,\r
319 EbcDebugProtocol\r
320 );\r
321 //\r
322 // This is recoverable, so free the memory and continue.\r
323 //\r
324 if (EFI_ERROR (Status)) {\r
325 gBS->FreePool (EbcDebugProtocol);\r
c91eaa3d 326 goto ErrorExit;\r
878ddf1f 327 }\r
c91eaa3d 328 //\r
329 // Install EbcDebugSupport Protocol Successfully\r
330 // Now we need to initialize the Ebc default Callback\r
331 //\r
332 Status = InitializeEbcCallback (EbcDebugProtocol);\r
333\r
878ddf1f 334 //\r
335 // Produce a VM test interface protocol. Not required for execution.\r
336 //\r
2ce31132 337 DEBUG_CODE_BEGIN ();\r
878ddf1f 338 InitEbcVmTestProtocol (&ImageHandle);\r
2ce31132 339 DEBUG_CODE_END ();\r
878ddf1f 340\r
c91eaa3d 341 return EFI_SUCCESS;\r
342\r
343ErrorExit:\r
344 HandleBuffer = NULL;\r
345 Status = gBS->LocateHandleBuffer (\r
346 ByProtocol,\r
347 &gEfiEbcProtocolGuid,\r
348 NULL,\r
349 &NumHandles,\r
350 &HandleBuffer\r
351 );\r
352 if (Status == EFI_SUCCESS) {\r
353 //\r
354 // Loop through the handles\r
355 //\r
356 for (Index = 0; Index < NumHandles; Index++) {\r
357 Status = gBS->HandleProtocol (\r
358 HandleBuffer[Index],\r
359 &gEfiEbcProtocolGuid,\r
360 (VOID **) &OldEbcProtocol\r
361 );\r
362 if (Status == EFI_SUCCESS) {\r
363 gBS->UninstallProtocolInterface (\r
364 HandleBuffer[Index],\r
365 &gEfiEbcProtocolGuid,\r
366 OldEbcProtocol\r
367 );\r
368 }\r
369 }\r
370 }\r
371\r
372 if (HandleBuffer != NULL) {\r
373 gBS->FreePool (HandleBuffer);\r
374 HandleBuffer = NULL;\r
375 }\r
376\r
377 gBS->FreePool (EbcProtocol);\r
378\r
878ddf1f 379 return Status;\r
380}\r
381\r
382STATIC\r
383EFI_STATUS\r
384EFIAPI\r
385EbcCreateThunk (\r
386 IN EFI_EBC_PROTOCOL *This,\r
387 IN EFI_HANDLE ImageHandle,\r
388 IN VOID *EbcEntryPoint,\r
389 OUT VOID **Thunk\r
390 )\r
391/*++\r
392\r
393Routine Description:\r
394 \r
395 This is the top-level routine plugged into the EBC protocol. Since thunks\r
396 are very processor-specific, from here we dispatch directly to the very \r
397 processor-specific routine EbcCreateThunks().\r
398\r
399Arguments:\r
400\r
401 This - protocol instance pointer\r
402 ImageHandle - handle to the image. The EBC interpreter may use this to keep\r
403 track of any resource allocations performed in loading and\r
404 executing the image.\r
405 EbcEntryPoint - the entry point for the image (as defined in the file header)\r
406 Thunk - pointer to thunk pointer where the address of the created\r
407 thunk is returned.\r
408\r
409Returns:\r
410\r
411 EFI_STATUS\r
412\r
413--*/\r
414{\r
415 EFI_STATUS Status;\r
416\r
417 Status = EbcCreateThunks (\r
418 ImageHandle,\r
419 EbcEntryPoint,\r
420 Thunk,\r
421 FLAG_THUNK_ENTRY_POINT\r
422 );\r
423 return Status;\r
424}\r
425\r
426STATIC\r
427EFI_STATUS\r
428EFIAPI\r
429EbcDebugGetMaximumProcessorIndex (\r
430 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
431 OUT UINTN *MaxProcessorIndex\r
432 )\r
433/*++\r
434\r
435Routine Description:\r
436 \r
437 This EBC debugger protocol service is called by the debug agent\r
438\r
439Arguments:\r
440\r
441 This - pointer to the caller's debug support protocol interface\r
442 MaxProcessorIndex - pointer to a caller allocated UINTN in which the maximum\r
443 processor index is returned.\r
444 \r
445Returns:\r
446\r
447 Standard EFI_STATUS\r
448\r
449--*/\r
450{\r
451 *MaxProcessorIndex = 0;\r
452 return EFI_SUCCESS;\r
453}\r
454\r
455STATIC\r
456EFI_STATUS\r
457EFIAPI\r
458EbcDebugRegisterPeriodicCallback (\r
459 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
460 IN UINTN ProcessorIndex,\r
461 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
462 )\r
463/*++\r
464\r
465Routine Description:\r
466 \r
467 This protocol service is called by the debug agent to register a function\r
468 for us to call on a periodic basis.\r
469 \r
470\r
471Arguments:\r
472\r
473 This - pointer to the caller's debug support protocol interface\r
474 PeriodicCallback - pointer to the function to call periodically\r
475\r
476Returns:\r
477\r
478 Always EFI_SUCCESS\r
479\r
480--*/\r
481{\r
3114b334 482 if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {\r
483 return EFI_INVALID_PARAMETER;\r
484 }\r
485 if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {\r
486 return EFI_ALREADY_STARTED;\r
487 }\r
488 \r
878ddf1f 489 mDebugPeriodicCallback = PeriodicCallback;\r
490 return EFI_SUCCESS;\r
491}\r
492\r
493STATIC\r
494EFI_STATUS\r
495EFIAPI\r
496EbcDebugRegisterExceptionCallback (\r
497 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
498 IN UINTN ProcessorIndex,\r
499 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,\r
500 IN EFI_EXCEPTION_TYPE ExceptionType\r
501 )\r
502/*++\r
503\r
504Routine Description:\r
505 \r
506 This protocol service is called by the debug agent to register a function\r
507 for us to call when we detect an exception.\r
508 \r
509\r
510Arguments:\r
511\r
512 This - pointer to the caller's debug support protocol interface\r
513 PeriodicCallback - pointer to the function to call periodically\r
514\r
515Returns:\r
516\r
517 Always EFI_SUCCESS\r
518\r
519--*/\r
520{\r
3114b334 521 if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {\r
522 return EFI_INVALID_PARAMETER;\r
523 }\r
524 if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {\r
525 return EFI_INVALID_PARAMETER;\r
526 }\r
527 if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {\r
528 return EFI_ALREADY_STARTED;\r
529 }\r
530 mDebugExceptionCallback[ExceptionType] = ExceptionCallback;\r
878ddf1f 531 return EFI_SUCCESS;\r
532}\r
533\r
534STATIC\r
535EFI_STATUS\r
536EFIAPI\r
537EbcDebugInvalidateInstructionCache (\r
538 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
539 IN UINTN ProcessorIndex,\r
540 IN VOID *Start,\r
541 IN UINT64 Length\r
542 )\r
543/*++\r
544\r
545Routine Description:\r
546 \r
547 This EBC debugger protocol service is called by the debug agent. Required\r
548 for DebugSupport compliance but is only stubbed out for EBC.\r
549\r
550Arguments:\r
551 \r
552Returns:\r
553\r
554 EFI_SUCCESS\r
555\r
556--*/\r
557{\r
558 return EFI_SUCCESS;\r
559}\r
560\r
561EFI_STATUS\r
562EbcDebugSignalException (\r
563 IN EFI_EXCEPTION_TYPE ExceptionType,\r
564 IN EXCEPTION_FLAGS ExceptionFlags,\r
565 IN VM_CONTEXT *VmPtr\r
566 )\r
567/*++\r
568\r
569Routine Description:\r
570\r
571 The VM interpreter calls this function when an exception is detected.\r
572 \r
573Arguments:\r
574\r
575 VmPtr - pointer to a VM context for passing info to the EFI debugger.\r
576\r
577Returns:\r
578\r
579 EFI_SUCCESS if it returns at all\r
580 \r
581--*/\r
582{\r
583 EFI_SYSTEM_CONTEXT_EBC EbcContext;\r
584 EFI_SYSTEM_CONTEXT SystemContext;\r
c91eaa3d 585\r
586 ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));\r
878ddf1f 587 //\r
588 // Save the exception in the context passed in\r
589 //\r
590 VmPtr->ExceptionFlags |= ExceptionFlags;\r
591 VmPtr->LastException = ExceptionType;\r
592 //\r
593 // If it's a fatal exception, then flag it in the VM context in case an\r
594 // attached debugger tries to return from it.\r
595 //\r
596 if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {\r
597 VmPtr->StopFlags |= STOPFLAG_APP_DONE;\r
598 }\r
c91eaa3d 599\r
878ddf1f 600 //\r
601 // If someone's registered for exception callbacks, then call them.\r
878ddf1f 602 //\r
c91eaa3d 603 // EBC driver will register default exception callback to report the\r
604 // status code via the status code API\r
605 //\r
606 if (mDebugExceptionCallback[ExceptionType] != NULL) {\r
607\r
608 //\r
609 // Initialize the context structure\r
610 //\r
611 EbcContext.R0 = VmPtr->R[0];\r
612 EbcContext.R1 = VmPtr->R[1];\r
613 EbcContext.R2 = VmPtr->R[2];\r
614 EbcContext.R3 = VmPtr->R[3];\r
615 EbcContext.R4 = VmPtr->R[4];\r
616 EbcContext.R5 = VmPtr->R[5];\r
617 EbcContext.R6 = VmPtr->R[6];\r
618 EbcContext.R7 = VmPtr->R[7];\r
619 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;\r
620 EbcContext.Flags = VmPtr->Flags;\r
621 EbcContext.ControlFlags = 0;\r
622 SystemContext.SystemContextEbc = &EbcContext;\r
623\r
3114b334 624 mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);\r
c91eaa3d 625 //\r
626 // Restore the context structure and continue to execute\r
627 //\r
628 VmPtr->R[0] = EbcContext.R0;\r
629 VmPtr->R[1] = EbcContext.R1;\r
630 VmPtr->R[2] = EbcContext.R2;\r
631 VmPtr->R[3] = EbcContext.R3;\r
632 VmPtr->R[4] = EbcContext.R4;\r
633 VmPtr->R[5] = EbcContext.R5;\r
634 VmPtr->R[6] = EbcContext.R6;\r
635 VmPtr->R[7] = EbcContext.R7;\r
636 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;\r
637 VmPtr->Flags = EbcContext.Flags;\r
878ddf1f 638 }\r
c91eaa3d 639 \r
640 return EFI_SUCCESS;\r
641}\r
642\r
92dda53e 643STATIC\r
c91eaa3d 644EFI_STATUS\r
645InitializeEbcCallback (\r
646 IN EFI_DEBUG_SUPPORT_PROTOCOL *This\r
647 )\r
648/*++\r
649\r
650Routine Description:\r
651\r
652 To install default Callback function for the VM interpreter.\r
653 \r
654Arguments:\r
655\r
656 This - pointer to the instance of DebugSupport protocol\r
657\r
658Returns:\r
659\r
660 None\r
661 \r
662--*/\r
663{\r
664 INTN Index;\r
665 EFI_STATUS Status;\r
666\r
878ddf1f 667 //\r
c91eaa3d 668 // For ExceptionCallback\r
878ddf1f 669 //\r
c91eaa3d 670 for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {\r
671 EbcDebugRegisterExceptionCallback (\r
672 This,\r
673 0,\r
674 CommonEbcExceptionHandler,\r
675 Index\r
676 );\r
878ddf1f 677 }\r
c91eaa3d 678\r
878ddf1f 679 //\r
c91eaa3d 680 // For PeriodicCallback\r
878ddf1f 681 //\r
c91eaa3d 682 Status = gBS->CreateEvent (\r
683 EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,\r
684 EFI_TPL_NOTIFY,\r
685 EbcPeriodicNotifyFunction,\r
686 &mVmPtr,\r
687 &mEbcPeriodicEvent\r
688 );\r
689 if (EFI_ERROR(Status)) {\r
690 return Status;\r
691 }\r
692\r
693 Status = gBS->SetTimer (\r
694 mEbcPeriodicEvent,\r
695 TimerPeriodic,\r
696 EBC_VM_PERIODIC_CALLBACK_RATE\r
697 );\r
698 if (EFI_ERROR(Status)) {\r
699 return Status;\r
878ddf1f 700 }\r
701\r
c91eaa3d 702 return EFI_SUCCESS;\r
703}\r
704\r
92dda53e 705STATIC\r
c91eaa3d 706VOID\r
707CommonEbcExceptionHandler (\r
708 IN EFI_EXCEPTION_TYPE InterruptType,\r
709 IN EFI_SYSTEM_CONTEXT SystemContext\r
710 )\r
711/*++\r
712\r
713Routine Description:\r
714\r
715 The default Exception Callback for the VM interpreter.\r
716 In this function, we report status code, and print debug information\r
717 about EBC_CONTEXT, then dead loop.\r
718 \r
719Arguments:\r
720\r
721 InterruptType - Interrupt type.\r
722 SystemContext - EBC system context.\r
723\r
724Returns:\r
725\r
726 None\r
727 \r
728--*/\r
729{\r
878ddf1f 730 //\r
c91eaa3d 731 // We deadloop here to make it easy to debug this issue.\r
878ddf1f 732 //\r
c91eaa3d 733 ASSERT (FALSE);\r
734\r
735 return ;\r
736}\r
737\r
92dda53e 738STATIC\r
c91eaa3d 739VOID\r
740EFIAPI\r
741EbcPeriodicNotifyFunction (\r
742 IN EFI_EVENT Event,\r
743 IN VOID *Context\r
744 )\r
745/*++\r
746\r
747Routine Description:\r
748\r
749 The periodic callback function for EBC VM interpreter, which is used\r
750 to support the EFI debug support protocol.\r
751 \r
752Arguments:\r
753\r
754 Event - The Periodic Callback Event.\r
755 Context - It should be the address of VM_CONTEXT pointer.\r
756\r
757Returns:\r
758\r
759 None.\r
760 \r
761--*/\r
762{\r
763 VM_CONTEXT *VmPtr;\r
764\r
765 VmPtr = *(VM_CONTEXT **)Context;\r
766\r
767 if (VmPtr != NULL) {\r
768 EbcDebugPeriodic (VmPtr);\r
878ddf1f 769 }\r
770\r
c91eaa3d 771 return ;\r
878ddf1f 772}\r
773\r
92dda53e 774STATIC\r
878ddf1f 775EFI_STATUS\r
776EbcDebugPeriodic (\r
777 IN VM_CONTEXT *VmPtr\r
778 )\r
779/*++\r
780\r
781Routine Description:\r
782\r
783 The VM interpreter calls this function on a periodic basis to support\r
784 the EFI debug support protocol.\r
785 \r
786Arguments:\r
787\r
788 VmPtr - pointer to a VM context for passing info to the debugger.\r
789\r
790Returns:\r
791\r
792 Standard EFI status.\r
793 \r
794--*/\r
795{\r
c91eaa3d 796 EFI_SYSTEM_CONTEXT_EBC EbcContext;\r
797 EFI_SYSTEM_CONTEXT SystemContext;\r
798 \r
799 //\r
800 // If someone's registered for periodic callbacks, then call them.\r
801 //\r
802 if (mDebugPeriodicCallback != NULL) {\r
803\r
804 //\r
805 // Initialize the context structure\r
806 //\r
807 EbcContext.R0 = VmPtr->R[0];\r
808 EbcContext.R1 = VmPtr->R[1];\r
809 EbcContext.R2 = VmPtr->R[2];\r
810 EbcContext.R3 = VmPtr->R[3];\r
811 EbcContext.R4 = VmPtr->R[4];\r
812 EbcContext.R5 = VmPtr->R[5];\r
813 EbcContext.R6 = VmPtr->R[6];\r
814 EbcContext.R7 = VmPtr->R[7];\r
815 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;\r
816 EbcContext.Flags = VmPtr->Flags;\r
817 EbcContext.ControlFlags = 0;\r
818 SystemContext.SystemContextEbc = &EbcContext;\r
819\r
820 mDebugPeriodicCallback (SystemContext);\r
821\r
822 //\r
823 // Restore the context structure and continue to execute\r
824 //\r
825 VmPtr->R[0] = EbcContext.R0;\r
826 VmPtr->R[1] = EbcContext.R1;\r
827 VmPtr->R[2] = EbcContext.R2;\r
828 VmPtr->R[3] = EbcContext.R3;\r
829 VmPtr->R[4] = EbcContext.R4;\r
830 VmPtr->R[5] = EbcContext.R5;\r
831 VmPtr->R[6] = EbcContext.R6;\r
832 VmPtr->R[7] = EbcContext.R7;\r
833 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;\r
834 VmPtr->Flags = EbcContext.Flags;\r
835 }\r
836 \r
878ddf1f 837 return EFI_SUCCESS;\r
838}\r
839\r
840STATIC\r
841EFI_STATUS\r
842EFIAPI\r
843EbcUnloadImage (\r
844 IN EFI_EBC_PROTOCOL *This,\r
845 IN EFI_HANDLE ImageHandle\r
846 )\r
847/*++\r
848\r
849Routine Description:\r
850 \r
851 This routine is called by the core when an image is being unloaded from \r
852 memory. Basically we now have the opportunity to do any necessary cleanup.\r
853 Typically this will include freeing any memory allocated for thunk-creation.\r
854\r
855Arguments:\r
856\r
857 This - protocol instance pointer\r
858 ImageHandle - handle to the image being unloaded.\r
859\r
860Returns:\r
861\r
862 EFI_INVALID_PARAMETER - the ImageHandle passed in was not found in\r
863 the internal list of EBC image handles.\r
864 EFI_STATUS - completed successfully\r
865\r
866--*/\r
867{\r
868 EBC_THUNK_LIST *ThunkList;\r
869 EBC_THUNK_LIST *NextThunkList;\r
870 EBC_IMAGE_LIST *ImageList;\r
871 EBC_IMAGE_LIST *PrevImageList;\r
872 //\r
873 // First go through our list of known image handles and see if we've already\r
874 // created an image list element for this image handle.\r
875 //\r
876 PrevImageList = NULL;\r
877 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {\r
878 if (ImageList->ImageHandle == ImageHandle) {\r
879 break;\r
880 }\r
881 //\r
882 // Save the previous so we can connect the lists when we remove this one\r
883 //\r
884 PrevImageList = ImageList;\r
885 }\r
886\r
887 if (ImageList == NULL) {\r
888 return EFI_INVALID_PARAMETER;\r
889 }\r
890 //\r
891 // Free up all the thunk buffers and thunks list elements for this image\r
892 // handle.\r
893 //\r
894 ThunkList = ImageList->ThunkList;\r
895 while (ThunkList != NULL) {\r
896 NextThunkList = ThunkList->Next;\r
897 gBS->FreePool (ThunkList->ThunkBuffer);\r
898 gBS->FreePool (ThunkList);\r
899 ThunkList = NextThunkList;\r
900 }\r
901 //\r
902 // Now remove this image list element from the chain\r
903 //\r
904 if (PrevImageList == NULL) {\r
905 //\r
906 // Remove from head\r
907 //\r
908 mEbcImageList = ImageList->Next;\r
909 } else {\r
910 PrevImageList->Next = ImageList->Next;\r
911 }\r
912 //\r
913 // Now free up the image list element\r
914 //\r
915 gBS->FreePool (ImageList);\r
916 return EFI_SUCCESS;\r
917}\r
918\r
919EFI_STATUS\r
920EbcAddImageThunk (\r
921 IN EFI_HANDLE ImageHandle,\r
922 IN VOID *ThunkBuffer,\r
923 IN UINT32 ThunkSize\r
924 )\r
925/*++\r
926\r
927Routine Description:\r
928 \r
929 Add a thunk to our list of thunks for a given image handle. \r
930 Also flush the instruction cache since we've written thunk code\r
931 to memory that will be executed eventually.\r
932\r
933Arguments:\r
934\r
935 ImageHandle - the image handle to which the thunk is tied\r
936 ThunkBuffer - the buffer we've created/allocated\r
937 ThunkSize - the size of the thunk memory allocated\r
938\r
939Returns:\r
940 \r
941 EFI_OUT_OF_RESOURCES - memory allocation failed\r
942 EFI_SUCCESS - successful completion\r
943\r
944--*/\r
945{\r
946 EBC_THUNK_LIST *ThunkList;\r
947 EBC_IMAGE_LIST *ImageList;\r
948 EFI_STATUS Status;\r
949\r
950 //\r
951 // It so far so good, then flush the instruction cache\r
952 //\r
953 if (mEbcICacheFlush != NULL) {\r
954 Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);\r
955 if (EFI_ERROR (Status)) {\r
956 return Status;\r
957 }\r
958 }\r
959 //\r
960 // Go through our list of known image handles and see if we've already\r
961 // created a image list element for this image handle.\r
962 //\r
963 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {\r
964 if (ImageList->ImageHandle == ImageHandle) {\r
965 break;\r
966 }\r
967 }\r
968\r
969 if (ImageList == NULL) {\r
970 //\r
971 // Allocate a new one\r
972 //\r
973 Status = gBS->AllocatePool (\r
974 EfiBootServicesData,\r
975 sizeof (EBC_IMAGE_LIST),\r
976 (VOID **) &ImageList\r
977 );\r
978 if (Status != EFI_SUCCESS) {\r
979 return EFI_OUT_OF_RESOURCES;\r
980 }\r
981\r
982 ImageList->ThunkList = NULL;\r
983 ImageList->ImageHandle = ImageHandle;\r
984 ImageList->Next = mEbcImageList;\r
985 mEbcImageList = ImageList;\r
986 }\r
987 //\r
988 // Ok, now create a new thunk element to add to the list\r
989 //\r
990 Status = gBS->AllocatePool (\r
991 EfiBootServicesData,\r
992 sizeof (EBC_THUNK_LIST),\r
993 (VOID **) &ThunkList\r
994 );\r
995 if (Status != EFI_SUCCESS) {\r
996 return EFI_OUT_OF_RESOURCES;\r
997 }\r
998 //\r
999 // Add it to the head of the list\r
1000 //\r
1001 ThunkList->Next = ImageList->ThunkList;\r
1002 ThunkList->ThunkBuffer = ThunkBuffer;\r
1003 ImageList->ThunkList = ThunkList;\r
1004 return EFI_SUCCESS;\r
1005}\r
1006\r
1007STATIC\r
1008EFI_STATUS\r
1009EFIAPI\r
1010EbcRegisterICacheFlush (\r
1011 IN EFI_EBC_PROTOCOL *This,\r
1012 IN EBC_ICACHE_FLUSH Flush\r
1013 )\r
1014{\r
1015 mEbcICacheFlush = Flush;\r
1016 return EFI_SUCCESS;\r
1017}\r
1018\r
1019STATIC\r
1020EFI_STATUS\r
1021EFIAPI\r
1022EbcGetVersion (\r
1023 IN EFI_EBC_PROTOCOL *This,\r
1024 IN OUT UINT64 *Version\r
1025 )\r
1026{\r
1027 if (Version == NULL) {\r
1028 return EFI_INVALID_PARAMETER;\r
1029 }\r
1030\r
1031 *Version = GetVmVersion ();\r
1032 return EFI_SUCCESS;\r
1033}\r
1034\r
1035STATIC\r
1036EFI_STATUS\r
1037InitEbcVmTestProtocol (\r
1038 IN EFI_HANDLE *IHandle\r
1039 )\r
1040/*++\r
1041\r
1042Routine Description:\r
1043 \r
1044 Produce an EBC VM test protocol that can be used for regression tests.\r
1045\r
1046Arguments:\r
1047\r
1048 IHandle - handle on which to install the protocol.\r
1049\r
1050Returns:\r
1051\r
1052 EFI_OUT_OF_RESOURCES - memory allocation failed\r
1053 EFI_SUCCESS - successful completion\r
1054\r
1055--*/\r
1056{\r
1057 EFI_HANDLE Handle;\r
1058 EFI_STATUS Status;\r
1059 EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;\r
1060\r
1061 //\r
1062 // Allocate memory for the protocol, then fill in the fields\r
1063 //\r
1064 Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_EBC_VM_TEST_PROTOCOL), (VOID **) &EbcVmTestProtocol);\r
1065 if (Status != EFI_SUCCESS) {\r
1066 return EFI_OUT_OF_RESOURCES;\r
1067 }\r
1068 EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;\r
1069\r
2ce31132 1070 DEBUG_CODE_BEGIN ();\r
878ddf1f 1071 EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;\r
1072 EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;\r
2ce31132 1073 DEBUG_CODE_END ();\r
878ddf1f 1074\r
1075 //\r
1076 // Publish the protocol\r
1077 //\r
1078 Handle = NULL;\r
1079 Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);\r
1080 if (EFI_ERROR (Status)) {\r
1081 gBS->FreePool (EbcVmTestProtocol);\r
1082 }\r
1083 return Status;\r
1084}\r
1085STATIC\r
1086EFI_STATUS\r
1087EbcVmTestUnsupported ()\r
1088{\r
1089 return EFI_UNSUPPORTED;\r
1090}\r
1091\r