3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Top level module for the EBC virtual machine implementation.
19 Provides auxilliary support routines for the VM. That is, routines
20 that are not particularly related to VM execution of EBC instructions.
25 #include "EbcExecute.h"
28 // We'll keep track of all thunks we create in a linked list. Each
29 // thunk is tied to an image handle, so we have a linked list of
30 // image handles, with each having a linked list of thunks allocated
31 // to that image handle.
33 typedef struct _EBC_THUNK_LIST
{
35 struct _EBC_THUNK_LIST
*Next
;
38 typedef struct _EBC_IMAGE_LIST
{
39 struct _EBC_IMAGE_LIST
*Next
;
40 EFI_HANDLE ImageHandle
;
41 EBC_THUNK_LIST
*ThunkList
;
48 IN EFI_EBC_PROTOCOL
*This
,
49 IN EFI_HANDLE ImageHandle
56 IN EFI_EBC_PROTOCOL
*This
,
57 IN EFI_HANDLE ImageHandle
,
58 IN VOID
*EbcEntryPoint
,
66 IN EFI_EBC_PROTOCOL
*This
,
67 IN OUT UINT64
*Version
73 InitializeEbcCallback (
74 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
80 CommonEbcExceptionHandler (
81 IN EFI_EXCEPTION_TYPE InterruptType
,
82 IN EFI_SYSTEM_CONTEXT SystemContext
88 EbcPeriodicNotifyFunction (
101 // These two functions and the GUID are used to produce an EBC test protocol.
102 // This functionality is definitely not required for execution.
106 InitEbcVmTestProtocol (
107 IN EFI_HANDLE
*Handle
112 EbcVmTestUnsupported (
119 EbcRegisterICacheFlush (
120 IN EFI_EBC_PROTOCOL
*This
,
121 IN EBC_ICACHE_FLUSH Flush
127 EbcDebugGetMaximumProcessorIndex (
128 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
129 OUT UINTN
*MaxProcessorIndex
135 EbcDebugRegisterPeriodicCallback (
136 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
137 IN UINTN ProcessorIndex
,
138 IN EFI_PERIODIC_CALLBACK PeriodicCallback
144 EbcDebugRegisterExceptionCallback (
145 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
146 IN UINTN ProcessorIndex
,
147 IN EFI_EXCEPTION_CALLBACK ExceptionCallback
,
148 IN EFI_EXCEPTION_TYPE ExceptionType
154 EbcDebugInvalidateInstructionCache (
155 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
156 IN UINTN ProcessorIndex
,
162 // We have one linked list of image handles for the whole world. Since
163 // there should only be one interpreter, make them global. They must
164 // also be global since the execution of an EBC image does not provide
167 static EBC_IMAGE_LIST
*mEbcImageList
= NULL
;
170 // Callback function to flush the icache after thunk creation
172 static EBC_ICACHE_FLUSH mEbcICacheFlush
;
175 // These get set via calls by the debug agent
177 static EFI_PERIODIC_CALLBACK mDebugPeriodicCallback
= NULL
;
178 static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback
[MAX_EBC_EXCEPTION
+ 1] = {NULL
};
179 static EFI_GUID mEfiEbcVmTestProtocolGuid
= EFI_EBC_VM_TEST_PROTOCOL_GUID
;
182 // Event for Periodic callback
184 static EFI_EVENT mEbcPeriodicEvent
;
185 VM_CONTEXT
*mVmPtr
= NULL
;
189 InitializeEbcDriver (
190 IN EFI_HANDLE ImageHandle
,
191 IN EFI_SYSTEM_TABLE
*SystemTable
197 Initializes the VM EFI interface. Allocates memory for the VM interface
198 and registers the VM protocol.
202 ImageHandle - EFI image handle.
203 SystemTable - Pointer to the EFI system table.
206 Standard EFI status code.
210 EFI_EBC_PROTOCOL
*EbcProtocol
;
211 EFI_EBC_PROTOCOL
*OldEbcProtocol
;
213 EFI_DEBUG_SUPPORT_PROTOCOL
*EbcDebugProtocol
;
214 EFI_HANDLE
*HandleBuffer
;
220 EbcDebugProtocol
= NULL
;
223 // Allocate memory for our protocol. Then fill in the blanks.
225 EbcProtocol
= AllocatePool (sizeof (EFI_EBC_PROTOCOL
));
227 if (EbcProtocol
== NULL
) {
228 return EFI_OUT_OF_RESOURCES
;
231 EbcProtocol
->CreateThunk
= EbcCreateThunk
;
232 EbcProtocol
->UnloadImage
= EbcUnloadImage
;
233 EbcProtocol
->RegisterICacheFlush
= EbcRegisterICacheFlush
;
234 EbcProtocol
->GetVersion
= EbcGetVersion
;
235 mEbcICacheFlush
= NULL
;
238 // Find any already-installed EBC protocols and uninstall them
242 Status
= gBS
->LocateHandleBuffer (
244 &gEfiEbcProtocolGuid
,
249 if (Status
== EFI_SUCCESS
) {
251 // Loop through the handles
253 for (Index
= 0; Index
< NumHandles
; Index
++) {
254 Status
= gBS
->HandleProtocol (
256 &gEfiEbcProtocolGuid
,
257 (VOID
**) &OldEbcProtocol
259 if (Status
== EFI_SUCCESS
) {
260 if (gBS
->ReinstallProtocolInterface (
262 &gEfiEbcProtocolGuid
,
272 if (HandleBuffer
!= NULL
) {
273 FreePool (HandleBuffer
);
277 // Add the protocol so someone can locate us if we haven't already.
280 Status
= gBS
->InstallProtocolInterface (
282 &gEfiEbcProtocolGuid
,
283 EFI_NATIVE_INTERFACE
,
286 if (EFI_ERROR (Status
)) {
287 FreePool (EbcProtocol
);
292 // Allocate memory for our debug protocol. Then fill in the blanks.
294 EbcDebugProtocol
= AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL
));
296 if (EbcDebugProtocol
== NULL
) {
300 EbcDebugProtocol
->Isa
= IsaEbc
;
301 EbcDebugProtocol
->GetMaximumProcessorIndex
= EbcDebugGetMaximumProcessorIndex
;
302 EbcDebugProtocol
->RegisterPeriodicCallback
= EbcDebugRegisterPeriodicCallback
;
303 EbcDebugProtocol
->RegisterExceptionCallback
= EbcDebugRegisterExceptionCallback
;
304 EbcDebugProtocol
->InvalidateInstructionCache
= EbcDebugInvalidateInstructionCache
;
307 // Add the protocol so the debug agent can find us
309 Status
= gBS
->InstallProtocolInterface (
311 &gEfiDebugSupportProtocolGuid
,
312 EFI_NATIVE_INTERFACE
,
316 // This is recoverable, so free the memory and continue.
318 if (EFI_ERROR (Status
)) {
319 FreePool (EbcDebugProtocol
);
323 // Install EbcDebugSupport Protocol Successfully
324 // Now we need to initialize the Ebc default Callback
326 Status
= InitializeEbcCallback (EbcDebugProtocol
);
329 // Produce a VM test interface protocol. Not required for execution.
332 InitEbcVmTestProtocol (&ImageHandle
);
339 Status
= gBS
->LocateHandleBuffer (
341 &gEfiEbcProtocolGuid
,
346 if (Status
== EFI_SUCCESS
) {
348 // Loop through the handles
350 for (Index
= 0; Index
< NumHandles
; Index
++) {
351 Status
= gBS
->HandleProtocol (
353 &gEfiEbcProtocolGuid
,
354 (VOID
**) &OldEbcProtocol
356 if (Status
== EFI_SUCCESS
) {
357 gBS
->UninstallProtocolInterface (
359 &gEfiEbcProtocolGuid
,
366 if (HandleBuffer
!= NULL
) {
367 FreePool (HandleBuffer
);
371 FreePool (EbcProtocol
);
380 IN EFI_EBC_PROTOCOL
*This
,
381 IN EFI_HANDLE ImageHandle
,
382 IN VOID
*EbcEntryPoint
,
389 This is the top-level routine plugged into the EBC protocol. Since thunks
390 are very processor-specific, from here we dispatch directly to the very
391 processor-specific routine EbcCreateThunks().
395 This - protocol instance pointer
396 ImageHandle - handle to the image. The EBC interpreter may use this to keep
397 track of any resource allocations performed in loading and
399 EbcEntryPoint - the entry point for the image (as defined in the file header)
400 Thunk - pointer to thunk pointer where the address of the created
411 Status
= EbcCreateThunks (
415 FLAG_THUNK_ENTRY_POINT
423 EbcDebugGetMaximumProcessorIndex (
424 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
425 OUT UINTN
*MaxProcessorIndex
431 This EBC debugger protocol service is called by the debug agent
435 This - pointer to the caller's debug support protocol interface
436 MaxProcessorIndex - pointer to a caller allocated UINTN in which the maximum
437 processor index is returned.
445 *MaxProcessorIndex
= 0;
452 EbcDebugRegisterPeriodicCallback (
453 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
454 IN UINTN ProcessorIndex
,
455 IN EFI_PERIODIC_CALLBACK PeriodicCallback
461 This protocol service is called by the debug agent to register a function
462 for us to call on a periodic basis.
467 This - pointer to the caller's debug support protocol interface
468 PeriodicCallback - pointer to the function to call periodically
476 if ((mDebugPeriodicCallback
== NULL
) && (PeriodicCallback
== NULL
)) {
477 return EFI_INVALID_PARAMETER
;
479 if ((mDebugPeriodicCallback
!= NULL
) && (PeriodicCallback
!= NULL
)) {
480 return EFI_ALREADY_STARTED
;
483 mDebugPeriodicCallback
= PeriodicCallback
;
490 EbcDebugRegisterExceptionCallback (
491 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
492 IN UINTN ProcessorIndex
,
493 IN EFI_EXCEPTION_CALLBACK ExceptionCallback
,
494 IN EFI_EXCEPTION_TYPE ExceptionType
500 This protocol service is called by the debug agent to register a function
501 for us to call when we detect an exception.
506 This - pointer to the caller's debug support protocol interface
507 PeriodicCallback - pointer to the function to call periodically
515 if ((ExceptionType
< 0) || (ExceptionType
> MAX_EBC_EXCEPTION
)) {
516 return EFI_INVALID_PARAMETER
;
518 if ((mDebugExceptionCallback
[ExceptionType
] == NULL
) && (ExceptionCallback
== NULL
)) {
519 return EFI_INVALID_PARAMETER
;
521 if ((mDebugExceptionCallback
[ExceptionType
] != NULL
) && (ExceptionCallback
!= NULL
)) {
522 return EFI_ALREADY_STARTED
;
524 mDebugExceptionCallback
[ExceptionType
] = ExceptionCallback
;
531 EbcDebugInvalidateInstructionCache (
532 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
,
533 IN UINTN ProcessorIndex
,
541 This EBC debugger protocol service is called by the debug agent. Required
542 for DebugSupport compliance but is only stubbed out for EBC.
556 EbcDebugSignalException (
557 IN EFI_EXCEPTION_TYPE ExceptionType
,
558 IN EXCEPTION_FLAGS ExceptionFlags
,
565 The VM interpreter calls this function when an exception is detected.
569 VmPtr - pointer to a VM context for passing info to the EFI debugger.
573 EFI_SUCCESS if it returns at all
577 EFI_SYSTEM_CONTEXT_EBC EbcContext
;
578 EFI_SYSTEM_CONTEXT SystemContext
;
580 ASSERT ((ExceptionType
>= 0) && (ExceptionType
<= MAX_EBC_EXCEPTION
));
582 // Save the exception in the context passed in
584 VmPtr
->ExceptionFlags
|= ExceptionFlags
;
585 VmPtr
->LastException
= ExceptionType
;
587 // If it's a fatal exception, then flag it in the VM context in case an
588 // attached debugger tries to return from it.
590 if (ExceptionFlags
& EXCEPTION_FLAG_FATAL
) {
591 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
595 // If someone's registered for exception callbacks, then call them.
597 // EBC driver will register default exception callback to report the
598 // status code via the status code API
600 if (mDebugExceptionCallback
[ExceptionType
] != NULL
) {
603 // Initialize the context structure
605 EbcContext
.R0
= VmPtr
->R
[0];
606 EbcContext
.R1
= VmPtr
->R
[1];
607 EbcContext
.R2
= VmPtr
->R
[2];
608 EbcContext
.R3
= VmPtr
->R
[3];
609 EbcContext
.R4
= VmPtr
->R
[4];
610 EbcContext
.R5
= VmPtr
->R
[5];
611 EbcContext
.R6
= VmPtr
->R
[6];
612 EbcContext
.R7
= VmPtr
->R
[7];
613 EbcContext
.Ip
= (UINT64
)(UINTN
)VmPtr
->Ip
;
614 EbcContext
.Flags
= VmPtr
->Flags
;
615 EbcContext
.ControlFlags
= 0;
616 SystemContext
.SystemContextEbc
= &EbcContext
;
618 mDebugExceptionCallback
[ExceptionType
] (ExceptionType
, SystemContext
);
620 // Restore the context structure and continue to execute
622 VmPtr
->R
[0] = EbcContext
.R0
;
623 VmPtr
->R
[1] = EbcContext
.R1
;
624 VmPtr
->R
[2] = EbcContext
.R2
;
625 VmPtr
->R
[3] = EbcContext
.R3
;
626 VmPtr
->R
[4] = EbcContext
.R4
;
627 VmPtr
->R
[5] = EbcContext
.R5
;
628 VmPtr
->R
[6] = EbcContext
.R6
;
629 VmPtr
->R
[7] = EbcContext
.R7
;
630 VmPtr
->Ip
= (VMIP
)(UINTN
)EbcContext
.Ip
;
631 VmPtr
->Flags
= EbcContext
.Flags
;
639 InitializeEbcCallback (
640 IN EFI_DEBUG_SUPPORT_PROTOCOL
*This
646 To install default Callback function for the VM interpreter.
650 This - pointer to the instance of DebugSupport protocol
662 // For ExceptionCallback
664 for (Index
= 0; Index
<= MAX_EBC_EXCEPTION
; Index
++) {
665 EbcDebugRegisterExceptionCallback (
668 CommonEbcExceptionHandler
,
674 // For PeriodicCallback
676 Status
= gBS
->CreateEvent (
677 EFI_EVENT_TIMER
| EFI_EVENT_NOTIFY_SIGNAL
,
679 EbcPeriodicNotifyFunction
,
683 if (EFI_ERROR(Status
)) {
687 Status
= gBS
->SetTimer (
690 EBC_VM_PERIODIC_CALLBACK_RATE
692 if (EFI_ERROR(Status
)) {
701 CommonEbcExceptionHandler (
702 IN EFI_EXCEPTION_TYPE InterruptType
,
703 IN EFI_SYSTEM_CONTEXT SystemContext
709 The default Exception Callback for the VM interpreter.
710 In this function, we report status code, and print debug information
711 about EBC_CONTEXT, then dead loop.
715 InterruptType - Interrupt type.
716 SystemContext - EBC system context.
725 // We deadloop here to make it easy to debug this issue.
735 EbcPeriodicNotifyFunction (
743 The periodic callback function for EBC VM interpreter, which is used
744 to support the EFI debug support protocol.
748 Event - The Periodic Callback Event.
749 Context - It should be the address of VM_CONTEXT pointer.
759 VmPtr
= *(VM_CONTEXT
**)Context
;
762 EbcDebugPeriodic (VmPtr
);
777 The VM interpreter calls this function on a periodic basis to support
778 the EFI debug support protocol.
782 VmPtr - pointer to a VM context for passing info to the debugger.
790 EFI_SYSTEM_CONTEXT_EBC EbcContext
;
791 EFI_SYSTEM_CONTEXT SystemContext
;
794 // If someone's registered for periodic callbacks, then call them.
796 if (mDebugPeriodicCallback
!= NULL
) {
799 // Initialize the context structure
801 EbcContext
.R0
= VmPtr
->R
[0];
802 EbcContext
.R1
= VmPtr
->R
[1];
803 EbcContext
.R2
= VmPtr
->R
[2];
804 EbcContext
.R3
= VmPtr
->R
[3];
805 EbcContext
.R4
= VmPtr
->R
[4];
806 EbcContext
.R5
= VmPtr
->R
[5];
807 EbcContext
.R6
= VmPtr
->R
[6];
808 EbcContext
.R7
= VmPtr
->R
[7];
809 EbcContext
.Ip
= (UINT64
)(UINTN
)VmPtr
->Ip
;
810 EbcContext
.Flags
= VmPtr
->Flags
;
811 EbcContext
.ControlFlags
= 0;
812 SystemContext
.SystemContextEbc
= &EbcContext
;
814 mDebugPeriodicCallback (SystemContext
);
817 // Restore the context structure and continue to execute
819 VmPtr
->R
[0] = EbcContext
.R0
;
820 VmPtr
->R
[1] = EbcContext
.R1
;
821 VmPtr
->R
[2] = EbcContext
.R2
;
822 VmPtr
->R
[3] = EbcContext
.R3
;
823 VmPtr
->R
[4] = EbcContext
.R4
;
824 VmPtr
->R
[5] = EbcContext
.R5
;
825 VmPtr
->R
[6] = EbcContext
.R6
;
826 VmPtr
->R
[7] = EbcContext
.R7
;
827 VmPtr
->Ip
= (VMIP
)(UINTN
)EbcContext
.Ip
;
828 VmPtr
->Flags
= EbcContext
.Flags
;
838 IN EFI_EBC_PROTOCOL
*This
,
839 IN EFI_HANDLE ImageHandle
845 This routine is called by the core when an image is being unloaded from
846 memory. Basically we now have the opportunity to do any necessary cleanup.
847 Typically this will include freeing any memory allocated for thunk-creation.
851 This - protocol instance pointer
852 ImageHandle - handle to the image being unloaded.
856 EFI_INVALID_PARAMETER - the ImageHandle passed in was not found in
857 the internal list of EBC image handles.
858 EFI_STATUS - completed successfully
862 EBC_THUNK_LIST
*ThunkList
;
863 EBC_THUNK_LIST
*NextThunkList
;
864 EBC_IMAGE_LIST
*ImageList
;
865 EBC_IMAGE_LIST
*PrevImageList
;
867 // First go through our list of known image handles and see if we've already
868 // created an image list element for this image handle.
870 PrevImageList
= NULL
;
871 for (ImageList
= mEbcImageList
; ImageList
!= NULL
; ImageList
= ImageList
->Next
) {
872 if (ImageList
->ImageHandle
== ImageHandle
) {
876 // Save the previous so we can connect the lists when we remove this one
878 PrevImageList
= ImageList
;
881 if (ImageList
== NULL
) {
882 return EFI_INVALID_PARAMETER
;
885 // Free up all the thunk buffers and thunks list elements for this image
888 ThunkList
= ImageList
->ThunkList
;
889 while (ThunkList
!= NULL
) {
890 NextThunkList
= ThunkList
->Next
;
891 FreePool (ThunkList
->ThunkBuffer
);
892 FreePool (ThunkList
);
893 ThunkList
= NextThunkList
;
896 // Now remove this image list element from the chain
898 if (PrevImageList
== NULL
) {
902 mEbcImageList
= ImageList
->Next
;
904 PrevImageList
->Next
= ImageList
->Next
;
907 // Now free up the image list element
909 FreePool (ImageList
);
915 IN EFI_HANDLE ImageHandle
,
916 IN VOID
*ThunkBuffer
,
923 Add a thunk to our list of thunks for a given image handle.
924 Also flush the instruction cache since we've written thunk code
925 to memory that will be executed eventually.
929 ImageHandle - the image handle to which the thunk is tied
930 ThunkBuffer - the buffer we've created/allocated
931 ThunkSize - the size of the thunk memory allocated
935 EFI_OUT_OF_RESOURCES - memory allocation failed
936 EFI_SUCCESS - successful completion
940 EBC_THUNK_LIST
*ThunkList
;
941 EBC_IMAGE_LIST
*ImageList
;
945 // It so far so good, then flush the instruction cache
947 if (mEbcICacheFlush
!= NULL
) {
948 Status
= mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS
) (UINTN
) ThunkBuffer
, ThunkSize
);
949 if (EFI_ERROR (Status
)) {
954 // Go through our list of known image handles and see if we've already
955 // created a image list element for this image handle.
957 for (ImageList
= mEbcImageList
; ImageList
!= NULL
; ImageList
= ImageList
->Next
) {
958 if (ImageList
->ImageHandle
== ImageHandle
) {
963 if (ImageList
== NULL
) {
965 // Allocate a new one
967 ImageList
= AllocatePool (sizeof (EBC_IMAGE_LIST
));
969 if (ImageList
== NULL
) {
970 return EFI_OUT_OF_RESOURCES
;
973 ImageList
->ThunkList
= NULL
;
974 ImageList
->ImageHandle
= ImageHandle
;
975 ImageList
->Next
= mEbcImageList
;
976 mEbcImageList
= ImageList
;
979 // Ok, now create a new thunk element to add to the list
981 ThunkList
= AllocatePool (sizeof (EBC_THUNK_LIST
));
983 if (ThunkList
== NULL
) {
984 return EFI_OUT_OF_RESOURCES
;
987 // Add it to the head of the list
989 ThunkList
->Next
= ImageList
->ThunkList
;
990 ThunkList
->ThunkBuffer
= ThunkBuffer
;
991 ImageList
->ThunkList
= ThunkList
;
998 EbcRegisterICacheFlush (
999 IN EFI_EBC_PROTOCOL
*This
,
1000 IN EBC_ICACHE_FLUSH Flush
1003 mEbcICacheFlush
= Flush
;
1011 IN EFI_EBC_PROTOCOL
*This
,
1012 IN OUT UINT64
*Version
1015 if (Version
== NULL
) {
1016 return EFI_INVALID_PARAMETER
;
1019 *Version
= GetVmVersion ();
1025 InitEbcVmTestProtocol (
1026 IN EFI_HANDLE
*IHandle
1030 Routine Description:
1032 Produce an EBC VM test protocol that can be used for regression tests.
1036 IHandle - handle on which to install the protocol.
1040 EFI_OUT_OF_RESOURCES - memory allocation failed
1041 EFI_SUCCESS - successful completion
1047 EFI_EBC_VM_TEST_PROTOCOL
*EbcVmTestProtocol
;
1050 // Allocate memory for the protocol, then fill in the fields
1052 EbcVmTestProtocol
= AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL
));
1053 if (EbcVmTestProtocol
== NULL
) {
1054 return EFI_OUT_OF_RESOURCES
;
1056 EbcVmTestProtocol
->Execute
= (EBC_VM_TEST_EXECUTE
) EbcExecuteInstructions
;
1058 DEBUG_CODE_BEGIN ();
1059 EbcVmTestProtocol
->Assemble
= (EBC_VM_TEST_ASM
) EbcVmTestUnsupported
;
1060 EbcVmTestProtocol
->Disassemble
= (EBC_VM_TEST_DASM
) EbcVmTestUnsupported
;
1064 // Publish the protocol
1067 Status
= gBS
->InstallProtocolInterface (&Handle
, &mEfiEbcVmTestProtocolGuid
, EFI_NATIVE_INTERFACE
, EbcVmTestProtocol
);
1068 if (EFI_ERROR (Status
)) {
1069 FreePool (EbcVmTestProtocol
);
1075 EbcVmTestUnsupported ()
1077 return EFI_UNSUPPORTED
;