]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c
Add some definitions for efi event in Uefi/UefiSpec.h to follow spec.
[mirror_edk2.git] / EdkModulePkg / Universal / Ebc / Dxe / EbcInt.c
CommitLineData
878ddf1f 1/*++\r
2\r
93b0fbc8 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
878ddf1f 8\r
93b0fbc8 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
878ddf1f 13\r
14 EbcInt.c\r
93b0fbc8 15\r
878ddf1f 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
93b0fbc8 21\r
878ddf1f 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
73ebf379 181static VOID* mStackBuffer[MAX_STACK_NUM];\r
182static EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];\r
183static UINTN mStackNum = 0;\r
184\r
c91eaa3d 185//\r
186// Event for Periodic callback\r
187//\r
188static EFI_EVENT mEbcPeriodicEvent;\r
189VM_CONTEXT *mVmPtr = NULL;\r
190\r
878ddf1f 191EFI_STATUS\r
192EFIAPI\r
193InitializeEbcDriver (\r
194 IN EFI_HANDLE ImageHandle,\r
195 IN EFI_SYSTEM_TABLE *SystemTable\r
196 )\r
197/*++\r
198\r
93b0fbc8 199Routine Description:\r
878ddf1f 200\r
93b0fbc8 201 Initializes the VM EFI interface. Allocates memory for the VM interface\r
878ddf1f 202 and registers the VM protocol.\r
203\r
93b0fbc8 204Arguments:\r
878ddf1f 205\r
206 ImageHandle - EFI image handle.\r
207 SystemTable - Pointer to the EFI system table.\r
208\r
93b0fbc8 209Returns:\r
878ddf1f 210 Standard EFI status code.\r
211\r
212--*/\r
213{\r
214 EFI_EBC_PROTOCOL *EbcProtocol;\r
215 EFI_EBC_PROTOCOL *OldEbcProtocol;\r
216 EFI_STATUS Status;\r
217 EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;\r
218 EFI_HANDLE *HandleBuffer;\r
219 UINTN NumHandles;\r
220 UINTN Index;\r
221 BOOLEAN Installed;\r
222\r
c91eaa3d 223 EbcProtocol = NULL;\r
224 EbcDebugProtocol = NULL;\r
225\r
878ddf1f 226 //\r
227 // Allocate memory for our protocol. Then fill in the blanks.\r
228 //\r
6626ad11
LG
229 EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));\r
230\r
231 if (EbcProtocol == NULL) {\r
878ddf1f 232 return EFI_OUT_OF_RESOURCES;\r
233 }\r
234\r
235 EbcProtocol->CreateThunk = EbcCreateThunk;\r
236 EbcProtocol->UnloadImage = EbcUnloadImage;\r
237 EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;\r
238 EbcProtocol->GetVersion = EbcGetVersion;\r
239 mEbcICacheFlush = NULL;\r
240\r
241 //\r
242 // Find any already-installed EBC protocols and uninstall them\r
243 //\r
244 Installed = FALSE;\r
245 HandleBuffer = NULL;\r
246 Status = gBS->LocateHandleBuffer (\r
247 ByProtocol,\r
248 &gEfiEbcProtocolGuid,\r
249 NULL,\r
250 &NumHandles,\r
251 &HandleBuffer\r
252 );\r
253 if (Status == EFI_SUCCESS) {\r
254 //\r
255 // Loop through the handles\r
256 //\r
257 for (Index = 0; Index < NumHandles; Index++) {\r
258 Status = gBS->HandleProtocol (\r
259 HandleBuffer[Index],\r
260 &gEfiEbcProtocolGuid,\r
261 (VOID **) &OldEbcProtocol\r
262 );\r
263 if (Status == EFI_SUCCESS) {\r
264 if (gBS->ReinstallProtocolInterface (\r
265 HandleBuffer[Index],\r
266 &gEfiEbcProtocolGuid,\r
267 OldEbcProtocol,\r
268 EbcProtocol\r
269 ) == EFI_SUCCESS) {\r
270 Installed = TRUE;\r
271 }\r
272 }\r
273 }\r
274 }\r
275\r
276 if (HandleBuffer != NULL) {\r
6626ad11 277 FreePool (HandleBuffer);\r
878ddf1f 278 HandleBuffer = NULL;\r
279 }\r
280 //\r
281 // Add the protocol so someone can locate us if we haven't already.\r
282 //\r
283 if (!Installed) {\r
284 Status = gBS->InstallProtocolInterface (\r
285 &ImageHandle,\r
286 &gEfiEbcProtocolGuid,\r
287 EFI_NATIVE_INTERFACE,\r
288 EbcProtocol\r
289 );\r
290 if (EFI_ERROR (Status)) {\r
6626ad11 291 FreePool (EbcProtocol);\r
878ddf1f 292 return Status;\r
293 }\r
294 }\r
73ebf379 295\r
296 Status = InitEBCStack();\r
297 if (EFI_ERROR(Status)) {\r
298 goto ErrorExit;\r
299 }\r
300\r
878ddf1f 301 //\r
302 // Allocate memory for our debug protocol. Then fill in the blanks.\r
303 //\r
6626ad11
LG
304 EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));\r
305\r
306 if (EbcDebugProtocol == NULL) {\r
c91eaa3d 307 goto ErrorExit;\r
878ddf1f 308 }\r
309\r
310 EbcDebugProtocol->Isa = IsaEbc;\r
311 EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;\r
312 EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;\r
313 EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;\r
314 EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;\r
315\r
316 //\r
317 // Add the protocol so the debug agent can find us\r
318 //\r
319 Status = gBS->InstallProtocolInterface (\r
320 &ImageHandle,\r
321 &gEfiDebugSupportProtocolGuid,\r
322 EFI_NATIVE_INTERFACE,\r
323 EbcDebugProtocol\r
324 );\r
325 //\r
326 // This is recoverable, so free the memory and continue.\r
327 //\r
328 if (EFI_ERROR (Status)) {\r
6626ad11 329 FreePool (EbcDebugProtocol);\r
c91eaa3d 330 goto ErrorExit;\r
878ddf1f 331 }\r
c91eaa3d 332 //\r
333 // Install EbcDebugSupport Protocol Successfully\r
334 // Now we need to initialize the Ebc default Callback\r
335 //\r
336 Status = InitializeEbcCallback (EbcDebugProtocol);\r
337\r
878ddf1f 338 //\r
339 // Produce a VM test interface protocol. Not required for execution.\r
340 //\r
2ce31132 341 DEBUG_CODE_BEGIN ();\r
878ddf1f 342 InitEbcVmTestProtocol (&ImageHandle);\r
2ce31132 343 DEBUG_CODE_END ();\r
878ddf1f 344\r
c91eaa3d 345 return EFI_SUCCESS;\r
346\r
347ErrorExit:\r
73ebf379 348 FreeEBCStack();\r
c91eaa3d 349 HandleBuffer = NULL;\r
350 Status = gBS->LocateHandleBuffer (\r
351 ByProtocol,\r
352 &gEfiEbcProtocolGuid,\r
353 NULL,\r
354 &NumHandles,\r
355 &HandleBuffer\r
356 );\r
357 if (Status == EFI_SUCCESS) {\r
358 //\r
359 // Loop through the handles\r
360 //\r
361 for (Index = 0; Index < NumHandles; Index++) {\r
362 Status = gBS->HandleProtocol (\r
363 HandleBuffer[Index],\r
364 &gEfiEbcProtocolGuid,\r
365 (VOID **) &OldEbcProtocol\r
366 );\r
367 if (Status == EFI_SUCCESS) {\r
368 gBS->UninstallProtocolInterface (\r
369 HandleBuffer[Index],\r
370 &gEfiEbcProtocolGuid,\r
371 OldEbcProtocol\r
372 );\r
373 }\r
374 }\r
375 }\r
376\r
377 if (HandleBuffer != NULL) {\r
6626ad11 378 FreePool (HandleBuffer);\r
c91eaa3d 379 HandleBuffer = NULL;\r
380 }\r
381\r
6626ad11 382 FreePool (EbcProtocol);\r
c91eaa3d 383\r
878ddf1f 384 return Status;\r
385}\r
386\r
387STATIC\r
388EFI_STATUS\r
389EFIAPI\r
390EbcCreateThunk (\r
391 IN EFI_EBC_PROTOCOL *This,\r
392 IN EFI_HANDLE ImageHandle,\r
393 IN VOID *EbcEntryPoint,\r
394 OUT VOID **Thunk\r
395 )\r
396/*++\r
397\r
398Routine Description:\r
93b0fbc8 399\r
878ddf1f 400 This is the top-level routine plugged into the EBC protocol. Since thunks\r
93b0fbc8 401 are very processor-specific, from here we dispatch directly to the very\r
878ddf1f 402 processor-specific routine EbcCreateThunks().\r
403\r
404Arguments:\r
405\r
406 This - protocol instance pointer\r
407 ImageHandle - handle to the image. The EBC interpreter may use this to keep\r
408 track of any resource allocations performed in loading and\r
409 executing the image.\r
410 EbcEntryPoint - the entry point for the image (as defined in the file header)\r
411 Thunk - pointer to thunk pointer where the address of the created\r
412 thunk is returned.\r
413\r
414Returns:\r
415\r
416 EFI_STATUS\r
417\r
418--*/\r
419{\r
420 EFI_STATUS Status;\r
421\r
422 Status = EbcCreateThunks (\r
423 ImageHandle,\r
424 EbcEntryPoint,\r
425 Thunk,\r
426 FLAG_THUNK_ENTRY_POINT\r
427 );\r
428 return Status;\r
429}\r
430\r
431STATIC\r
432EFI_STATUS\r
433EFIAPI\r
434EbcDebugGetMaximumProcessorIndex (\r
435 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
436 OUT UINTN *MaxProcessorIndex\r
437 )\r
438/*++\r
439\r
440Routine Description:\r
93b0fbc8 441\r
878ddf1f 442 This EBC debugger protocol service is called by the debug agent\r
443\r
444Arguments:\r
445\r
446 This - pointer to the caller's debug support protocol interface\r
447 MaxProcessorIndex - pointer to a caller allocated UINTN in which the maximum\r
448 processor index is returned.\r
93b0fbc8 449\r
878ddf1f 450Returns:\r
451\r
452 Standard EFI_STATUS\r
453\r
454--*/\r
455{\r
456 *MaxProcessorIndex = 0;\r
457 return EFI_SUCCESS;\r
458}\r
459\r
460STATIC\r
461EFI_STATUS\r
462EFIAPI\r
463EbcDebugRegisterPeriodicCallback (\r
464 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
465 IN UINTN ProcessorIndex,\r
466 IN EFI_PERIODIC_CALLBACK PeriodicCallback\r
467 )\r
468/*++\r
469\r
470Routine Description:\r
93b0fbc8 471\r
878ddf1f 472 This protocol service is called by the debug agent to register a function\r
473 for us to call on a periodic basis.\r
93b0fbc8 474\r
878ddf1f 475\r
476Arguments:\r
477\r
478 This - pointer to the caller's debug support protocol interface\r
479 PeriodicCallback - pointer to the function to call periodically\r
480\r
481Returns:\r
482\r
483 Always EFI_SUCCESS\r
484\r
485--*/\r
486{\r
3114b334 487 if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {\r
488 return EFI_INVALID_PARAMETER;\r
489 }\r
490 if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {\r
491 return EFI_ALREADY_STARTED;\r
492 }\r
93b0fbc8 493\r
878ddf1f 494 mDebugPeriodicCallback = PeriodicCallback;\r
495 return EFI_SUCCESS;\r
496}\r
497\r
498STATIC\r
499EFI_STATUS\r
500EFIAPI\r
501EbcDebugRegisterExceptionCallback (\r
502 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
503 IN UINTN ProcessorIndex,\r
504 IN EFI_EXCEPTION_CALLBACK ExceptionCallback,\r
505 IN EFI_EXCEPTION_TYPE ExceptionType\r
506 )\r
507/*++\r
508\r
509Routine Description:\r
93b0fbc8 510\r
878ddf1f 511 This protocol service is called by the debug agent to register a function\r
512 for us to call when we detect an exception.\r
93b0fbc8 513\r
878ddf1f 514\r
515Arguments:\r
516\r
517 This - pointer to the caller's debug support protocol interface\r
73ebf379 518 ExceptionCallback - pointer to the function to the exception\r
878ddf1f 519\r
520Returns:\r
521\r
522 Always EFI_SUCCESS\r
523\r
524--*/\r
525{\r
3114b334 526 if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {\r
527 return EFI_INVALID_PARAMETER;\r
528 }\r
529 if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {\r
530 return EFI_INVALID_PARAMETER;\r
531 }\r
532 if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {\r
533 return EFI_ALREADY_STARTED;\r
534 }\r
535 mDebugExceptionCallback[ExceptionType] = ExceptionCallback;\r
878ddf1f 536 return EFI_SUCCESS;\r
537}\r
538\r
539STATIC\r
540EFI_STATUS\r
541EFIAPI\r
542EbcDebugInvalidateInstructionCache (\r
543 IN EFI_DEBUG_SUPPORT_PROTOCOL *This,\r
544 IN UINTN ProcessorIndex,\r
545 IN VOID *Start,\r
546 IN UINT64 Length\r
547 )\r
548/*++\r
549\r
550Routine Description:\r
93b0fbc8 551\r
878ddf1f 552 This EBC debugger protocol service is called by the debug agent. Required\r
553 for DebugSupport compliance but is only stubbed out for EBC.\r
554\r
555Arguments:\r
93b0fbc8 556\r
878ddf1f 557Returns:\r
558\r
559 EFI_SUCCESS\r
560\r
561--*/\r
562{\r
563 return EFI_SUCCESS;\r
564}\r
565\r
566EFI_STATUS\r
567EbcDebugSignalException (\r
568 IN EFI_EXCEPTION_TYPE ExceptionType,\r
569 IN EXCEPTION_FLAGS ExceptionFlags,\r
570 IN VM_CONTEXT *VmPtr\r
571 )\r
572/*++\r
573\r
574Routine Description:\r
575\r
576 The VM interpreter calls this function when an exception is detected.\r
93b0fbc8 577\r
878ddf1f 578Arguments:\r
579\r
580 VmPtr - pointer to a VM context for passing info to the EFI debugger.\r
581\r
582Returns:\r
583\r
584 EFI_SUCCESS if it returns at all\r
93b0fbc8 585\r
878ddf1f 586--*/\r
587{\r
588 EFI_SYSTEM_CONTEXT_EBC EbcContext;\r
589 EFI_SYSTEM_CONTEXT SystemContext;\r
c91eaa3d 590\r
591 ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));\r
878ddf1f 592 //\r
593 // Save the exception in the context passed in\r
594 //\r
595 VmPtr->ExceptionFlags |= ExceptionFlags;\r
596 VmPtr->LastException = ExceptionType;\r
597 //\r
598 // If it's a fatal exception, then flag it in the VM context in case an\r
599 // attached debugger tries to return from it.\r
600 //\r
601 if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {\r
602 VmPtr->StopFlags |= STOPFLAG_APP_DONE;\r
603 }\r
c91eaa3d 604\r
878ddf1f 605 //\r
606 // If someone's registered for exception callbacks, then call them.\r
878ddf1f 607 //\r
c91eaa3d 608 // EBC driver will register default exception callback to report the\r
609 // status code via the status code API\r
610 //\r
611 if (mDebugExceptionCallback[ExceptionType] != NULL) {\r
612\r
613 //\r
614 // Initialize the context structure\r
615 //\r
616 EbcContext.R0 = VmPtr->R[0];\r
617 EbcContext.R1 = VmPtr->R[1];\r
618 EbcContext.R2 = VmPtr->R[2];\r
619 EbcContext.R3 = VmPtr->R[3];\r
620 EbcContext.R4 = VmPtr->R[4];\r
621 EbcContext.R5 = VmPtr->R[5];\r
622 EbcContext.R6 = VmPtr->R[6];\r
623 EbcContext.R7 = VmPtr->R[7];\r
624 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;\r
625 EbcContext.Flags = VmPtr->Flags;\r
626 EbcContext.ControlFlags = 0;\r
627 SystemContext.SystemContextEbc = &EbcContext;\r
628\r
3114b334 629 mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);\r
c91eaa3d 630 //\r
631 // Restore the context structure and continue to execute\r
632 //\r
633 VmPtr->R[0] = EbcContext.R0;\r
634 VmPtr->R[1] = EbcContext.R1;\r
635 VmPtr->R[2] = EbcContext.R2;\r
636 VmPtr->R[3] = EbcContext.R3;\r
637 VmPtr->R[4] = EbcContext.R4;\r
638 VmPtr->R[5] = EbcContext.R5;\r
639 VmPtr->R[6] = EbcContext.R6;\r
640 VmPtr->R[7] = EbcContext.R7;\r
641 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;\r
642 VmPtr->Flags = EbcContext.Flags;\r
878ddf1f 643 }\r
93b0fbc8 644\r
c91eaa3d 645 return EFI_SUCCESS;\r
646}\r
647\r
92dda53e 648STATIC\r
c91eaa3d 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
93b0fbc8 658\r
c91eaa3d 659Arguments:\r
660\r
661 This - pointer to the instance of DebugSupport protocol\r
662\r
663Returns:\r
664\r
665 None\r
93b0fbc8 666\r
c91eaa3d 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
93b0fbc8 688 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
689 TPL_NOTIFY,\r
c91eaa3d 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
92dda53e 710STATIC\r
c91eaa3d 711VOID\r
712CommonEbcExceptionHandler (\r
713 IN EFI_EXCEPTION_TYPE InterruptType,\r
714 IN EFI_SYSTEM_CONTEXT SystemContext\r
715 )\r
716/*++\r
717\r
718Routine Description:\r
719\r
720 The default Exception Callback for the VM interpreter.\r
721 In this function, we report status code, and print debug information\r
722 about EBC_CONTEXT, then dead loop.\r
93b0fbc8 723\r
c91eaa3d 724Arguments:\r
725\r
726 InterruptType - Interrupt type.\r
727 SystemContext - EBC system context.\r
728\r
729Returns:\r
730\r
731 None\r
93b0fbc8 732\r
c91eaa3d 733--*/\r
734{\r
878ddf1f 735 //\r
c91eaa3d 736 // We deadloop here to make it easy to debug this issue.\r
878ddf1f 737 //\r
c91eaa3d 738 ASSERT (FALSE);\r
739\r
740 return ;\r
741}\r
742\r
92dda53e 743STATIC\r
c91eaa3d 744VOID\r
745EFIAPI\r
746EbcPeriodicNotifyFunction (\r
747 IN EFI_EVENT Event,\r
748 IN VOID *Context\r
749 )\r
750/*++\r
751\r
752Routine Description:\r
753\r
754 The periodic callback function for EBC VM interpreter, which is used\r
755 to support the EFI debug support protocol.\r
93b0fbc8 756\r
c91eaa3d 757Arguments:\r
758\r
759 Event - The Periodic Callback Event.\r
760 Context - It should be the address of VM_CONTEXT pointer.\r
761\r
762Returns:\r
763\r
764 None.\r
93b0fbc8 765\r
c91eaa3d 766--*/\r
767{\r
768 VM_CONTEXT *VmPtr;\r
769\r
770 VmPtr = *(VM_CONTEXT **)Context;\r
771\r
772 if (VmPtr != NULL) {\r
773 EbcDebugPeriodic (VmPtr);\r
878ddf1f 774 }\r
775\r
c91eaa3d 776 return ;\r
878ddf1f 777}\r
778\r
92dda53e 779STATIC\r
878ddf1f 780EFI_STATUS\r
781EbcDebugPeriodic (\r
782 IN VM_CONTEXT *VmPtr\r
783 )\r
784/*++\r
785\r
786Routine Description:\r
787\r
788 The VM interpreter calls this function on a periodic basis to support\r
789 the EFI debug support protocol.\r
93b0fbc8 790\r
878ddf1f 791Arguments:\r
792\r
793 VmPtr - pointer to a VM context for passing info to the debugger.\r
794\r
795Returns:\r
796\r
797 Standard EFI status.\r
93b0fbc8 798\r
878ddf1f 799--*/\r
800{\r
c91eaa3d 801 EFI_SYSTEM_CONTEXT_EBC EbcContext;\r
802 EFI_SYSTEM_CONTEXT SystemContext;\r
93b0fbc8 803\r
c91eaa3d 804 //\r
805 // If someone's registered for periodic callbacks, then call them.\r
806 //\r
807 if (mDebugPeriodicCallback != NULL) {\r
808\r
809 //\r
810 // Initialize the context structure\r
811 //\r
812 EbcContext.R0 = VmPtr->R[0];\r
813 EbcContext.R1 = VmPtr->R[1];\r
814 EbcContext.R2 = VmPtr->R[2];\r
815 EbcContext.R3 = VmPtr->R[3];\r
816 EbcContext.R4 = VmPtr->R[4];\r
817 EbcContext.R5 = VmPtr->R[5];\r
818 EbcContext.R6 = VmPtr->R[6];\r
819 EbcContext.R7 = VmPtr->R[7];\r
820 EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;\r
821 EbcContext.Flags = VmPtr->Flags;\r
822 EbcContext.ControlFlags = 0;\r
823 SystemContext.SystemContextEbc = &EbcContext;\r
824\r
825 mDebugPeriodicCallback (SystemContext);\r
826\r
827 //\r
828 // Restore the context structure and continue to execute\r
829 //\r
830 VmPtr->R[0] = EbcContext.R0;\r
831 VmPtr->R[1] = EbcContext.R1;\r
832 VmPtr->R[2] = EbcContext.R2;\r
833 VmPtr->R[3] = EbcContext.R3;\r
834 VmPtr->R[4] = EbcContext.R4;\r
835 VmPtr->R[5] = EbcContext.R5;\r
836 VmPtr->R[6] = EbcContext.R6;\r
837 VmPtr->R[7] = EbcContext.R7;\r
838 VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;\r
839 VmPtr->Flags = EbcContext.Flags;\r
840 }\r
93b0fbc8 841\r
878ddf1f 842 return EFI_SUCCESS;\r
843}\r
844\r
845STATIC\r
846EFI_STATUS\r
847EFIAPI\r
848EbcUnloadImage (\r
849 IN EFI_EBC_PROTOCOL *This,\r
850 IN EFI_HANDLE ImageHandle\r
851 )\r
852/*++\r
853\r
854Routine Description:\r
93b0fbc8 855\r
856 This routine is called by the core when an image is being unloaded from\r
878ddf1f 857 memory. Basically we now have the opportunity to do any necessary cleanup.\r
858 Typically this will include freeing any memory allocated for thunk-creation.\r
859\r
860Arguments:\r
861\r
862 This - protocol instance pointer\r
863 ImageHandle - handle to the image being unloaded.\r
864\r
865Returns:\r
866\r
867 EFI_INVALID_PARAMETER - the ImageHandle passed in was not found in\r
868 the internal list of EBC image handles.\r
869 EFI_STATUS - completed successfully\r
870\r
871--*/\r
872{\r
873 EBC_THUNK_LIST *ThunkList;\r
874 EBC_THUNK_LIST *NextThunkList;\r
875 EBC_IMAGE_LIST *ImageList;\r
876 EBC_IMAGE_LIST *PrevImageList;\r
877 //\r
878 // First go through our list of known image handles and see if we've already\r
879 // created an image list element for this image handle.\r
880 //\r
73ebf379 881 ReturnEBCStackByHandle(ImageHandle);\r
878ddf1f 882 PrevImageList = NULL;\r
883 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {\r
884 if (ImageList->ImageHandle == ImageHandle) {\r
885 break;\r
886 }\r
887 //\r
888 // Save the previous so we can connect the lists when we remove this one\r
889 //\r
890 PrevImageList = ImageList;\r
891 }\r
892\r
893 if (ImageList == NULL) {\r
894 return EFI_INVALID_PARAMETER;\r
895 }\r
896 //\r
897 // Free up all the thunk buffers and thunks list elements for this image\r
898 // handle.\r
899 //\r
900 ThunkList = ImageList->ThunkList;\r
901 while (ThunkList != NULL) {\r
902 NextThunkList = ThunkList->Next;\r
6626ad11
LG
903 FreePool (ThunkList->ThunkBuffer);\r
904 FreePool (ThunkList);\r
878ddf1f 905 ThunkList = NextThunkList;\r
906 }\r
907 //\r
908 // Now remove this image list element from the chain\r
909 //\r
910 if (PrevImageList == NULL) {\r
911 //\r
912 // Remove from head\r
913 //\r
914 mEbcImageList = ImageList->Next;\r
915 } else {\r
916 PrevImageList->Next = ImageList->Next;\r
917 }\r
918 //\r
919 // Now free up the image list element\r
920 //\r
6626ad11 921 FreePool (ImageList);\r
878ddf1f 922 return EFI_SUCCESS;\r
923}\r
924\r
925EFI_STATUS\r
926EbcAddImageThunk (\r
927 IN EFI_HANDLE ImageHandle,\r
928 IN VOID *ThunkBuffer,\r
929 IN UINT32 ThunkSize\r
930 )\r
931/*++\r
932\r
933Routine Description:\r
93b0fbc8 934\r
935 Add a thunk to our list of thunks for a given image handle.\r
878ddf1f 936 Also flush the instruction cache since we've written thunk code\r
937 to memory that will be executed eventually.\r
938\r
939Arguments:\r
940\r
941 ImageHandle - the image handle to which the thunk is tied\r
942 ThunkBuffer - the buffer we've created/allocated\r
943 ThunkSize - the size of the thunk memory allocated\r
944\r
945Returns:\r
93b0fbc8 946\r
878ddf1f 947 EFI_OUT_OF_RESOURCES - memory allocation failed\r
948 EFI_SUCCESS - successful completion\r
949\r
950--*/\r
951{\r
952 EBC_THUNK_LIST *ThunkList;\r
953 EBC_IMAGE_LIST *ImageList;\r
954 EFI_STATUS Status;\r
955\r
956 //\r
957 // It so far so good, then flush the instruction cache\r
958 //\r
959 if (mEbcICacheFlush != NULL) {\r
960 Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);\r
961 if (EFI_ERROR (Status)) {\r
962 return Status;\r
963 }\r
964 }\r
965 //\r
966 // Go through our list of known image handles and see if we've already\r
967 // created a image list element for this image handle.\r
968 //\r
969 for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {\r
970 if (ImageList->ImageHandle == ImageHandle) {\r
971 break;\r
972 }\r
973 }\r
974\r
975 if (ImageList == NULL) {\r
976 //\r
977 // Allocate a new one\r
978 //\r
6626ad11
LG
979 ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));\r
980\r
981 if (ImageList == NULL) {\r
878ddf1f 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
6626ad11
LG
993 ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));\r
994\r
995 if (ThunkList == NULL) {\r
878ddf1f 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
73ebf379 1035EFI_STATUS\r
1036GetEBCStack(\r
1037 EFI_HANDLE Handle,\r
1038 VOID **StackBuffer,\r
1039 UINTN *BufferIndex\r
1040 )\r
1041{\r
1042 UINTN Index;\r
1043 EFI_TPL OldTpl;\r
93b0fbc8 1044 OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);\r
73ebf379 1045 for (Index = 0; Index < mStackNum; Index ++) {\r
1046 if (mStackBufferIndex[Index] == NULL) {\r
1047 mStackBufferIndex[Index] = Handle;\r
1048 break;\r
1049 }\r
1050 }\r
1051 gBS->RestoreTPL(OldTpl);\r
1052 if (Index == mStackNum) {\r
1053 return EFI_OUT_OF_RESOURCES;\r
1054 }\r
1055 *BufferIndex = Index;\r
1056 *StackBuffer = mStackBuffer[Index];\r
1057 return EFI_SUCCESS;\r
1058}\r
1059\r
1060EFI_STATUS\r
1061ReturnEBCStack(\r
1062 UINTN Index\r
1063 )\r
1064{\r
1065 mStackBufferIndex[Index] =NULL;\r
1066 return EFI_SUCCESS;\r
1067}\r
1068\r
1069EFI_STATUS\r
1070ReturnEBCStackByHandle(\r
1071 EFI_HANDLE Handle\r
1072 )\r
1073{\r
1074 UINTN Index;\r
1075 for (Index = 0; Index < mStackNum; Index ++) {\r
1076 if (mStackBufferIndex[Index] == Handle) {\r
1077 break;\r
1078 }\r
1079 }\r
1080 if (Index == mStackNum) {\r
1081 return EFI_NOT_FOUND;\r
1082 }\r
1083 mStackBufferIndex[Index] = NULL;\r
1084 return EFI_SUCCESS;\r
1085}\r
1086\r
1087EFI_STATUS\r
1088InitEBCStack (\r
1089 VOID\r
1090 )\r
1091{\r
1092 for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {\r
1093 mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);\r
1094 mStackBufferIndex[mStackNum] = NULL;\r
1095 if (mStackBuffer[mStackNum] == NULL) {\r
1096 break;\r
1097 }\r
1098 }\r
1099 if (mStackNum == 0) {\r
1100 return EFI_OUT_OF_RESOURCES;\r
1101 }\r
1102 return EFI_SUCCESS;\r
1103}\r
1104\r
1105EFI_STATUS\r
1106FreeEBCStack(\r
1107 VOID\r
1108 )\r
1109{\r
1110 UINTN Index;\r
1111 for (Index = 0; Index < mStackNum; Index ++) {\r
1112 FreePool(mStackBuffer[Index]);\r
1113 }\r
1114 return EFI_SUCCESS;\r
1115}\r
878ddf1f 1116STATIC\r
1117EFI_STATUS\r
1118InitEbcVmTestProtocol (\r
1119 IN EFI_HANDLE *IHandle\r
1120 )\r
1121/*++\r
1122\r
1123Routine Description:\r
93b0fbc8 1124\r
878ddf1f 1125 Produce an EBC VM test protocol that can be used for regression tests.\r
1126\r
1127Arguments:\r
1128\r
1129 IHandle - handle on which to install the protocol.\r
1130\r
1131Returns:\r
1132\r
1133 EFI_OUT_OF_RESOURCES - memory allocation failed\r
1134 EFI_SUCCESS - successful completion\r
1135\r
1136--*/\r
1137{\r
1138 EFI_HANDLE Handle;\r
1139 EFI_STATUS Status;\r
1140 EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;\r
1141\r
1142 //\r
1143 // Allocate memory for the protocol, then fill in the fields\r
1144 //\r
6626ad11
LG
1145 EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));\r
1146 if (EbcVmTestProtocol == NULL) {\r
878ddf1f 1147 return EFI_OUT_OF_RESOURCES;\r
1148 }\r
1149 EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;\r
1150\r
2ce31132 1151 DEBUG_CODE_BEGIN ();\r
878ddf1f 1152 EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;\r
1153 EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;\r
2ce31132 1154 DEBUG_CODE_END ();\r
878ddf1f 1155\r
1156 //\r
1157 // Publish the protocol\r
1158 //\r
1159 Handle = NULL;\r
1160 Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);\r
1161 if (EFI_ERROR (Status)) {\r
6626ad11 1162 FreePool (EbcVmTestProtocol);\r
878ddf1f 1163 }\r
1164 return Status;\r
1165}\r
1166STATIC\r
1167EFI_STATUS\r
1168EbcVmTestUnsupported ()\r
1169{\r
1170 return EFI_UNSUPPORTED;\r
1171}\r
1172\r