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