| ;/** @file | |
| ; | |
| ; This code provides low level routines that support the Virtual Machine. | |
| ; for option ROMs. | |
| ; | |
| ; Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> | |
| ; Copyright (c) 2014 Hewlett-Packard Development Company, L.P.<BR> | |
| ; This program and the accompanying materials | |
| ; are licensed and made available under the terms and conditions of the BSD License | |
| ; which accompanies this distribution. The full text of the license may be found at | |
| ; http://opensource.org/licenses/bsd-license.php | |
| ; | |
| ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| ; | |
| ;**/ | |
| ;--------------------------------------------------------------------------- | |
| ; Equate files needed. | |
| ;--------------------------------------------------------------------------- | |
| DEFAULT REL | |
| SECTION .text | |
| extern ASM_PFX(CopyMem) | |
| extern ASM_PFX(EbcInterpret) | |
| extern ASM_PFX(ExecuteEbcImageEntryPoint) | |
| ;**************************************************************************** | |
| ; EbcLLCALLEX | |
| ; | |
| ; This function is called to execute an EBC CALLEX instruction. | |
| ; This instruction requires that we thunk out to external native | |
| ; code. For x64, we switch stacks, copy the arguments to the stack | |
| ; and jump to the specified function. | |
| ; On return, we restore the stack pointer to its original location. | |
| ; | |
| ; Destroys no working registers. | |
| ;**************************************************************************** | |
| ; INT64 EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr) | |
| global ASM_PFX(EbcLLCALLEXNative) | |
| ASM_PFX(EbcLLCALLEXNative): | |
| push rbp | |
| push rbx | |
| mov rbp, rsp | |
| ; Function prolog | |
| ; Copy FuncAddr to a preserved register. | |
| mov rbx, rcx | |
| ; Set stack pointer to new value | |
| sub r8, rdx | |
| ; | |
| ; Fix X64 native function call prolog. Prepare space for at least 4 arguments, | |
| ; even if the native function's arguments are less than 4. | |
| ; | |
| ; From MSDN x64 Software Conventions, Overview of x64 Calling Conventions: | |
| ; "The caller is responsible for allocating space for parameters to the | |
| ; callee, and must always allocate sufficient space for the 4 register | |
| ; parameters, even if the callee doesn't have that many parameters. | |
| ; This aids in the simplicity of supporting C unprototyped functions, | |
| ; and vararg C/C++ functions." | |
| ; | |
| cmp r8, 0x20 | |
| jae skip_expansion | |
| mov r8, dword 0x20 | |
| skip_expansion: | |
| sub rsp, r8 | |
| ; | |
| ; Fix X64 native function call 16-byte alignment. | |
| ; | |
| ; From MSDN x64 Software Conventions, Stack Usage: | |
| ; "The stack will always be maintained 16-byte aligned, except within | |
| ; the prolog (for example, after the return address is pushed)." | |
| ; | |
| and rsp, ~ 0xf | |
| mov rcx, rsp | |
| sub rsp, 0x20 | |
| call ASM_PFX(CopyMem) | |
| add rsp, 0x20 | |
| ; Considering the worst case, load 4 potiential arguments | |
| ; into registers. | |
| mov rcx, qword [rsp] | |
| mov rdx, qword [rsp+0x8] | |
| mov r8, qword [rsp+0x10] | |
| mov r9, qword [rsp+0x18] | |
| ; Now call the external routine | |
| call rbx | |
| ; Function epilog | |
| mov rsp, rbp | |
| pop rbx | |
| pop rbp | |
| ret | |
| ;**************************************************************************** | |
| ; EbcLLEbcInterpret | |
| ; | |
| ; Begin executing an EBC image. | |
| ;**************************************************************************** | |
| ; UINT64 EbcLLEbcInterpret(VOID) | |
| global ASM_PFX(EbcLLEbcInterpret) | |
| ASM_PFX(EbcLLEbcInterpret): | |
| ; | |
| ;; mov rax, ca112ebccall2ebch | |
| ;; mov r10, EbcEntryPoint | |
| ;; mov r11, EbcLLEbcInterpret | |
| ;; jmp r11 | |
| ; | |
| ; Caller uses above instruction to jump here | |
| ; The stack is below: | |
| ; +-----------+ | |
| ; | RetAddr | | |
| ; +-----------+ | |
| ; |EntryPoint | (R10) | |
| ; +-----------+ | |
| ; | Arg1 | <- RDI | |
| ; +-----------+ | |
| ; | Arg2 | | |
| ; +-----------+ | |
| ; | ... | | |
| ; +-----------+ | |
| ; | Arg16 | | |
| ; +-----------+ | |
| ; | Dummy | | |
| ; +-----------+ | |
| ; | RDI | | |
| ; +-----------+ | |
| ; | RSI | | |
| ; +-----------+ | |
| ; | RBP | <- RBP | |
| ; +-----------+ | |
| ; | RetAddr | <- RSP is here | |
| ; +-----------+ | |
| ; | Scratch1 | (RCX) <- RSI | |
| ; +-----------+ | |
| ; | Scratch2 | (RDX) | |
| ; +-----------+ | |
| ; | Scratch3 | (R8) | |
| ; +-----------+ | |
| ; | Scratch4 | (R9) | |
| ; +-----------+ | |
| ; | Arg5 | | |
| ; +-----------+ | |
| ; | Arg6 | | |
| ; +-----------+ | |
| ; | ... | | |
| ; +-----------+ | |
| ; | Arg16 | | |
| ; +-----------+ | |
| ; | |
| ; save old parameter to stack | |
| mov [rsp + 0x8], rcx | |
| mov [rsp + 0x10], rdx | |
| mov [rsp + 0x18], r8 | |
| mov [rsp + 0x20], r9 | |
| ; Construct new stack | |
| push rbp | |
| mov rbp, rsp | |
| push rsi | |
| push rdi | |
| push rbx | |
| sub rsp, 0x80 | |
| push r10 | |
| mov rsi, rbp | |
| add rsi, 0x10 | |
| mov rdi, rsp | |
| add rdi, 8 | |
| mov rcx, dword 16 | |
| rep movsq | |
| ; build new paramater calling convention | |
| mov r9, [rsp + 0x18] | |
| mov r8, [rsp + 0x10] | |
| mov rdx, [rsp + 0x8] | |
| mov rcx, r10 | |
| ; call C-code | |
| call ASM_PFX(EbcInterpret) | |
| add rsp, 0x88 | |
| pop rbx | |
| pop rdi | |
| pop rsi | |
| pop rbp | |
| ret | |
| ;**************************************************************************** | |
| ; EbcLLExecuteEbcImageEntryPoint | |
| ; | |
| ; Begin executing an EBC image. | |
| ;**************************************************************************** | |
| ; UINT64 EbcLLExecuteEbcImageEntryPoint(VOID) | |
| global ASM_PFX(EbcLLExecuteEbcImageEntryPoint) | |
| ASM_PFX(EbcLLExecuteEbcImageEntryPoint): | |
| ; | |
| ;; mov rax, ca112ebccall2ebch | |
| ;; mov r10, EbcEntryPoint | |
| ;; mov r11, EbcLLExecuteEbcImageEntryPoint | |
| ;; jmp r11 | |
| ; | |
| ; Caller uses above instruction to jump here | |
| ; The stack is below: | |
| ; +-----------+ | |
| ; | RetAddr | | |
| ; +-----------+ | |
| ; |EntryPoint | (R10) | |
| ; +-----------+ | |
| ; |ImageHandle| | |
| ; +-----------+ | |
| ; |SystemTable| | |
| ; +-----------+ | |
| ; | Dummy | | |
| ; +-----------+ | |
| ; | Dummy | | |
| ; +-----------+ | |
| ; | RetAddr | <- RSP is here | |
| ; +-----------+ | |
| ; |ImageHandle| (RCX) | |
| ; +-----------+ | |
| ; |SystemTable| (RDX) | |
| ; +-----------+ | |
| ; | |
| ; build new paramater calling convention | |
| mov r8, rdx | |
| mov rdx, rcx | |
| mov rcx, r10 | |
| ; call C-code | |
| sub rsp, 0x28 | |
| call ASM_PFX(ExecuteEbcImageEntryPoint) | |
| add rsp, 0x28 | |
| ret | |