/** Create thunks for an EBC image entry point, or an EBC protocol service. @param ImageHandle Image handle for the EBC image. If not null, then we're creating a thunk for an image entry point. @param EbcEntryPoint Address of the EBC code that the thunk is to call @param Thunk Returned thunk we create here @param Flags Flags indicating options for creating the thunk @retval EFI_SUCCESS The thunk was created successfully. @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit aligned. @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC Thunk. @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough. **/ EFI_STATUS EbcCreateThunks ( IN EFI_HANDLE ImageHandle, IN VOID *EbcEntryPoint, OUT VOID **Thunk, IN UINT32 Flags ) { EBC_INSTRUCTION_BUFFER *InstructionBuffer; // // Check alignment of pointer to EBC code // if ((UINT32) (UINTN) EbcEntryPoint & 0x01) { return EFI_INVALID_PARAMETER; } InstructionBuffer = AllocatePool (sizeof (EBC_INSTRUCTION_BUFFER)); if (InstructionBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } // // Give them the address of our buffer we're going to fix up // *Thunk = InstructionBuffer; // // Copy whole thunk instruction buffer template // CopyMem (InstructionBuffer, &mEbcInstructionBufferTemplate, sizeof (EBC_INSTRUCTION_BUFFER)); // // Patch EbcEntryPoint and EbcLLEbcInterpret // InstructionBuffer->EbcEntryPoint = (UINT64)EbcEntryPoint; if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) { InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLExecuteEbcImageEntryPoint; } else { InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLEbcInterpret; } // // Add the thunk to the list for this image. Do this last since the add // function flushes the cache for us. // EbcAddImageThunk (ImageHandle, InstructionBuffer, sizeof (EBC_INSTRUCTION_BUFFER)); return EFI_SUCCESS; }
/** Create thunks for an EBC image entry point, or an EBC protocol service. @param ImageHandle Image handle for the EBC image. If not null, then we're creating a thunk for an image entry point. @param EbcEntryPoint Address of the EBC code that the thunk is to call @param Thunk Returned thunk we create here @param Flags Flags indicating options for creating the thunk @retval EFI_SUCCESS The thunk was created successfully. @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit aligned. @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC Thunk. @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough. **/ EFI_STATUS EbcCreateThunks ( IN EFI_HANDLE ImageHandle, IN VOID *EbcEntryPoint, OUT VOID **Thunk, IN UINT32 Flags ) { UINT8 *Ptr; UINT8 *ThunkBase; UINT32 Index; INT32 ThunkSize; // // Check alignment of pointer to EBC code // if ((UINT32) (UINTN) EbcEntryPoint & 0x01) { return EFI_INVALID_PARAMETER; } ThunkSize = sizeof(mInstructionBufferTemplate); Ptr = AllocatePool (sizeof(mInstructionBufferTemplate)); if (Ptr == NULL) { return EFI_OUT_OF_RESOURCES; } // // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr); // // Save the start address so we can add a pointer to it to a list later. // ThunkBase = Ptr; // // Give them the address of our buffer we're going to fix up // *Thunk = (VOID *) Ptr; // // Copy whole thunk instruction buffer template // CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)); // // Patch EbcEntryPoint and EbcLLEbcInterpret // for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) { if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) { *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint; } if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) { if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) { *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint; } else { *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret; } } } // // Add the thunk to the list for this image. Do this last since the add // function flushes the cache for us. // EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize); return EFI_SUCCESS; }
/** Create thunks for an EBC image entry point, or an EBC protocol service. @param ImageHandle Image handle for the EBC image. If not null, then we're creating a thunk for an image entry point. @param EbcEntryPoint Address of the EBC code that the thunk is to call @param Thunk Returned thunk we create here @param Flags Flags indicating options for creating the thunk @retval EFI_SUCCESS The thunk was created successfully. @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit aligned. @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC Thunk. @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough. **/ EFI_STATUS EbcCreateThunks ( IN EFI_HANDLE ImageHandle, IN VOID *EbcEntryPoint, OUT VOID **Thunk, IN UINT32 Flags ) { UINT8 *Ptr; UINT8 *ThunkBase; UINT32 Index; UINT32 Addr; INT32 Size; INT32 ThunkSize; // // Check alignment of pointer to EBC code // if ((UINT32) (UINTN) EbcEntryPoint & 0x01) { return EFI_INVALID_PARAMETER; } Size = EBC_THUNK_SIZE; ThunkSize = Size; Ptr = AllocatePool (Size); if (Ptr == NULL) { return EFI_OUT_OF_RESOURCES; } // // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr); // // Save the start address so we can add a pointer to it to a list later. // ThunkBase = Ptr; // // Give them the address of our buffer we're going to fix up // *Thunk = (VOID *) Ptr; // // Add a magic code here to help the VM recognize the thunk.. // mov eax, 0xca112ebc => B8 BC 2E 11 CA // *Ptr = 0xB8; Ptr++; Size--; Addr = (UINT32) 0xCA112EBC; for (Index = 0; Index < sizeof (Addr); Index++) { *Ptr = (UINT8) (UINTN) Addr; Addr >>= 8; Ptr++; Size--; } // // Add code bytes to load up a processor register with the EBC entry point. // mov eax, 0xaa55aa55 => B8 55 AA 55 AA // The first 8 bytes of the thunk entry is the address of the EBC // entry point. // *Ptr = 0xB8; Ptr++; Size--; Addr = (UINT32) EbcEntryPoint; for (Index = 0; Index < sizeof (Addr); Index++) { *Ptr = (UINT8) (UINTN) Addr; Addr >>= 8; Ptr++; Size--; } // // Stick in a load of ecx with the address of appropriate VM function. // mov ecx 12345678h => 0xB9 0x78 0x56 0x34 0x12 // if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) { Addr = (UINT32) (UINTN) ExecuteEbcImageEntryPoint; } else { Addr = (UINT32) (UINTN) EbcInterpret; } // // MOV ecx // *Ptr = 0xB9; Ptr++; Size--; for (Index = 0; Index < sizeof (Addr); Index++) { *Ptr = (UINT8) Addr; Addr >>= 8; Ptr++; Size--; } // // Stick in jump opcode bytes for jmp ecx => 0xFF 0xE1 // *Ptr = 0xFF; Ptr++; Size--; *Ptr = 0xE1; Size--; // // Double check that our defined size is ok (application error) // if (Size < 0) { ASSERT (FALSE); return EFI_BUFFER_TOO_SMALL; } // // Add the thunk to the list for this image. Do this last since the add // function flushes the cache for us. // EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize); return EFI_SUCCESS; }