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