summaryrefslogtreecommitdiffstats
path: root/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp')
-rw-r--r--src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp296
1 files changed, 296 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp
new file mode 100644
index 00000000..6611f667
--- /dev/null
+++ b/src/libs/xpcom18a4/xpcom/reflect/xptcall/src/md/unix/xptcinvoke_arm64_vbox.cpp
@@ -0,0 +1,296 @@
+/* $Id: xptcinvoke_arm64_vbox.cpp $ */
+/** @file
+ * XPCOM - Implementation XPTC_InvokeByIndex for arm64.
+ */
+
+/*
+ * Copyright (C) 2021-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "xptcprivate.h"
+#include <iprt/cdefs.h>
+#include <iprt/alloca.h>
+#include <iprt/assert.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define NUM_ARGS_IN_GPRS 8 /**< Number of arguments passed in general purpose registers (starting with x0). */
+#define NUM_ARGS_IN_FPRS 8 /**< Number of arguments passed in floating point registers (starting with d0). */
+
+#define MY_MAX_ARGS 64 /**< Limit ourselves to 64 arguments. */
+
+
+
+AssertCompileMemberOffset(nsXPTCVariant, val, 0);
+
+extern "C" __attribute__((naked)) nsresult
+arm64AsmInvoker(uintptr_t pfnMethod /*x0*/, uint32_t cParams /*w1*/, nsXPTCVariant *paParams /*x2*/, uint64_t cbStack /*x3*/,
+ uint8_t *acbStackArgs /*x4*/, uint64_t *pauGprArgs /*x5*/, uint64_t *pauFprArgs /*x6*/, uint32_t cFprArgs /*x7*/)
+{
+ __asm__ __volatile__(
+ /* Prologue - create the frame. */ "\
+ sub sp, sp, 16 \n\
+ stp x29, x30, [sp] \n\
+ mov x29, sp \n\
+ .cfi_def_cfa x29, 16 \n\
+ .cfi_rel_offset x30, -8 \n\
+ .cfi_rel_offset x29, -16 \n\
+\n\
+" /* Move pfnMethod to x16 and pauGprArgs to x7 free up x0 and x5: */ "\
+ mov x16, x0 \n\
+ mov x17, x5 \n\
+\n\
+" /* Load FPU registers first so we free up x6 & x7 early: */ "\
+ cmp w7, #0 \n\
+ b.eq Lno_fprs\n\
+ ldp d0, d1, [x6] \n\
+ ldp d2, d3, [x6, #16] \n\
+ ldp d4, d5, [x6, #32] \n\
+ ldp d6, d7, [x6, #48] \n\
+Lno_fprs:\n\
+\n\
+" /* Do argument passing by stack (if any). We align the stack to 16 bytes. */ "\
+ cmp x3, #0 \n\
+ beq Lno_stack_args \n\
+ sub x3, sp, x3 \n\
+ bic x3, x3, #15 \n\
+ mov sp, x3 \n\
+Lnext_parameter: \n\
+ ldrb w7, [x4] \n\
+ cmp w7, #0 \n\
+ beq Ladvance\n\
+\n\
+ cmp w7, #4 \n\
+ bgt Lstore_64bits\n\
+ cmp w7, #1 \n\
+ beq Lstore_8bits\n\
+ cmp w7, #2 \n\
+ beq Lstore_16bits\n\
+\n\
+Lstore_32bits:\n\
+ ldr w0, [x2] \n\
+ add x3, x3, #3 \n\
+ bic x3, x3, #3 \n\
+ str w0, [x3] \n"
+#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */
+" add x3, x3, #4 \n"
+#endif
+" b Ladvance \n\
+\n\
+Lstore_8bits:\n\
+ ldrb w0, [x2] \n\
+ strb w0, [x3] \n"
+#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */
+" add x3, x3, #1 \n"
+#endif
+" b Ladvance \n\
+\n\
+Lstore_16bits:\n\
+ ldrh w0, [x2] \n\
+ add x3, x3, #1 \n\
+ bic x3, x3, #1 \n\
+ strh w0, [x3] \n"
+#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */
+" add x3, x3, #2 \n"
+#endif
+" b Ladvance \n\
+\n\
+Lstore_64bits_ptr:\n\
+ ldr x0, [x2, %[offPtrInXPTCVariant]] \n\
+ b Lstore_64bits_common \n\
+Lstore_64bits:\n\
+ tst w7, #0x80 \n\
+ bne Lstore_64bits_ptr \n\
+ ldr x0, [x2] \n\
+Lstore_64bits_common:\n\
+ add x3, x3, #7 \n\
+ bic x3, x3, #7 \n\
+ str x0, [x3] \n"
+#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */
+" add x3, x3, #8 \n"
+#endif
+"\n\
+Ladvance:\n"
+#ifndef RT_OS_DARWIN /* macOS compacts stack usage. */
+" add x3, x3, #8 \n"
+#endif
+" add x4, x4, #1 \n\
+ add x2, x2, %[cbXPTCVariant] \n\
+ sub w1, w1, #1 \n\
+ cmp w1, #0 \n\
+ bne Lnext_parameter \n\
+\n\
+" /* reserve stack space for the integer and floating point registers and save them: */ "\
+Lno_stack_args: \n\
+\n\
+" /* Load general purpose argument registers: */ "\
+ ldp x0, x1, [x17] \n\
+ ldp x2, x3, [x17, #16] \n\
+ ldp x4, x5, [x17, #32] \n\
+ ldp x6, x7, [x17, #48] \n\
+\n\
+" /* Make the call: */ "\
+ blr x16 \n\
+\n\
+" /* Epilogue (clang does not emit the .cfi's here, so drop them too?): */ "\
+ mov sp, x29 \n\
+ ldp x29, x30, [sp] \n\
+ add sp, sp, #16 \n\
+ .cfi_def_cfa sp, 0 \n\
+ .cfi_restore x29 \n\
+ .cfi_restore x30 \n\
+ ret \n\
+" :
+ : [cbXPTCVariant] "i" (sizeof(nsXPTCVariant))
+ , [offPtrInXPTCVariant] "i" (offsetof(nsXPTCVariant, ptr))
+ :);
+}
+
+
+XPTC_PUBLIC_API(nsresult)
+XPTC_InvokeByIndex(nsISupports *pThis, PRUint32 idxMethod, PRUint32 cParams, nsXPTCVariant *paParams)
+{
+ AssertMsgReturn(cParams <= MY_MAX_ARGS, ("cParams=%#x idxMethod=%#x\n", cParams, idxMethod), NS_ERROR_UNEXPECTED);
+
+ /*
+ * Prepare
+ */
+ uint64_t auGprArgs[NUM_ARGS_IN_GPRS] = {0};
+ uint64_t auFprArgs[NUM_ARGS_IN_GPRS] = {0};
+ uint8_t acbStackArgs[MY_MAX_ARGS]; /* The number of value bytes to copy onto the stack. Zero if in register. */
+ uint32_t cbStackArgs = 0;
+ uint32_t cFprArgs = 0;
+ uint32_t cGprArgs = 0;
+
+ /* First argument is always 'pThis'. The 'pThis' argument is not accounted
+ for in cParams or acbStackArgs. */
+ auGprArgs[cGprArgs++] = (uintptr_t)pThis;
+
+ /* Do the other arguments. */
+ for (PRUint32 i = 0; i < cParams; i++)
+ {
+ if (paParams[i].IsPtrData())
+ {
+ if (cGprArgs < NUM_ARGS_IN_GPRS)
+ {
+ auGprArgs[cGprArgs++] = (uintptr_t)paParams[i].ptr;
+ acbStackArgs[i] = 0;
+ }
+ else
+ {
+ acbStackArgs[i] = sizeof(paParams[i].ptr) | UINT8_C(0x80);
+#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */
+ cbStackArgs = RT_ALIGN_32(cbStackArgs, sizeof(paParams[i].ptr)) + sizeof(paParams[i].ptr);
+#else
+ cbStackArgs += sizeof(uint64_t);
+#endif
+ }
+ }
+ else
+ {
+ if ( paParams[i].type != nsXPTType::T_FLOAT
+ && paParams[i].type != nsXPTType::T_DOUBLE)
+ {
+ if (cGprArgs < NUM_ARGS_IN_GPRS)
+ {
+ switch (paParams[i].type)
+ {
+ case nsXPTType::T_I8: auGprArgs[cGprArgs++] = paParams[i].val.i8; break;
+ case nsXPTType::T_I16: auGprArgs[cGprArgs++] = paParams[i].val.i16; break;
+ case nsXPTType::T_I32: auGprArgs[cGprArgs++] = paParams[i].val.i32; break;
+ case nsXPTType::T_I64: auGprArgs[cGprArgs++] = paParams[i].val.i64; break;
+ case nsXPTType::T_U8: auGprArgs[cGprArgs++] = paParams[i].val.u8; break;
+ case nsXPTType::T_U16: auGprArgs[cGprArgs++] = paParams[i].val.u16; break;
+ case nsXPTType::T_U32: auGprArgs[cGprArgs++] = paParams[i].val.u32; break;
+ default:
+ case nsXPTType::T_U64: auGprArgs[cGprArgs++] = paParams[i].val.u64; break;
+ case nsXPTType::T_BOOL: auGprArgs[cGprArgs++] = paParams[i].val.b; break;
+ case nsXPTType::T_CHAR: auGprArgs[cGprArgs++] = paParams[i].val.c; break;
+ case nsXPTType::T_WCHAR: auGprArgs[cGprArgs++] = paParams[i].val.wc; break;
+ }
+ acbStackArgs[i] = 0;
+ }
+ else
+ {
+ uint8_t cbStack;
+ switch (paParams[i].type)
+ {
+ case nsXPTType::T_I8: cbStack = sizeof(paParams[i].val.i8); break;
+ case nsXPTType::T_I16: cbStack = sizeof(paParams[i].val.i16); break;
+ case nsXPTType::T_I32: cbStack = sizeof(paParams[i].val.i32); break;
+ case nsXPTType::T_I64: cbStack = sizeof(paParams[i].val.i64); break;
+ case nsXPTType::T_U8: cbStack = sizeof(paParams[i].val.u8); break;
+ case nsXPTType::T_U16: cbStack = sizeof(paParams[i].val.u16); break;
+ case nsXPTType::T_U32: cbStack = sizeof(paParams[i].val.u32); break;
+ default:
+ case nsXPTType::T_U64: cbStack = sizeof(paParams[i].val.u64); break;
+ case nsXPTType::T_BOOL: cbStack = sizeof(paParams[i].val.b); break;
+ case nsXPTType::T_CHAR: cbStack = sizeof(paParams[i].val.c); break;
+ case nsXPTType::T_WCHAR: cbStack = sizeof(paParams[i].val.wc); break;
+ }
+ acbStackArgs[i] = cbStack;
+#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */
+ cbStackArgs = RT_ALIGN_32(cbStackArgs, cbStack) + cbStack;
+#else
+ cbStackArgs += sizeof(uint64_t);
+#endif
+ }
+ }
+ else if (cFprArgs < NUM_ARGS_IN_FPRS)
+ {
+ AssertCompile(sizeof(paParams[i].val.f) == 4);
+ AssertCompile(sizeof(paParams[i].val.d) == 8);
+ if (paParams[i].type == nsXPTType::T_FLOAT)
+ auFprArgs[cFprArgs++] = paParams[i].val.u32;
+ else
+ auFprArgs[cFprArgs++] = paParams[i].val.u64;
+ acbStackArgs[i] = 0;
+ }
+ else
+ {
+ uint8_t cbStack;
+ if (paParams[i].type == nsXPTType::T_FLOAT)
+ cbStack = sizeof(paParams[i].val.f);
+ else
+ cbStack = sizeof(paParams[i].val.d);
+ acbStackArgs[i] = cbStack;
+#ifdef RT_OS_DARWIN /* macOS compacts stack usage. */
+ cbStackArgs = RT_ALIGN_32(cbStackArgs, cbStack) + cbStack;
+#else
+ cbStackArgs += sizeof(uint64_t);
+#endif
+ }
+ }
+ }
+
+ /*
+ * Pass it on to a naked wrapper function that does the nitty gritty work.
+ */
+ uintptr_t *pauVtable = *(uintptr_t **)pThis;
+ return arm64AsmInvoker(pauVtable[idxMethod], cParams, paParams, cbStackArgs, acbStackArgs, auGprArgs, auFprArgs, cFprArgs);
+}
+