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