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