From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pd0-f178.google.com (mail-pd0-f178.google.com [209.85.192.178]) by mail.openembedded.org (Postfix) with ESMTP id 459A673AFC for ; Wed, 11 Mar 2015 13:42:09 +0000 (UTC) Received: by pdbnh10 with SMTP id nh10so11379221pdb.3 for ; Wed, 11 Mar 2015 06:42:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:content-type:content-transfer-encoding; bh=zBZZWw0zyhzXQx2XcQt4I/koZdqv/0Hrs3Sn/h/u12w=; b=tX3j/yxVHRCHgssIZ/InNzhxqk8MhYzDyTAcSWsvPtvyNQgwJeVsXAd3hMvc2iYRPj 9nCdwXYxMOMtzNv5vF5+3YgmaFx9mw0CpEnsVcH472w2D+VZmSpzR/h/MKkdP08QMas4 uxtrjQDHbnGvbNLfkzQEe4+d7hZscnpqEbUBZEnsG4QVbRjMQUoy6H7zyjCyThviJFgR /ligF1qa4Kh4jNRt/2OBdHA248qh57FKA/AklO0uee8VcRrVFZteCtc+jwLAMnM/SRYA GZnLIhU9gB/8HtzYvyHLFMbWCJsEAOuRqx3C7njLQQcArdf4c1RgO/3Vx75DivfoTO/X EfBg== X-Received: by 10.70.53.40 with SMTP id y8mr47755783pdo.61.1426081330559; Wed, 11 Mar 2015 06:42:10 -0700 (PDT) Received: from ?IPv6:2601:c:a700:3ba7:e194:b091:aa3f:a598? ([2601:c:a700:3ba7:e194:b091:aa3f:a598]) by mx.google.com with ESMTPSA id x1sm868779pdp.1.2015.03.11.06.42.08 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 11 Mar 2015 06:42:09 -0700 (PDT) Message-ID: <5500462D.7070408@gmail.com> Date: Wed, 11 Mar 2015 06:42:05 -0700 From: akuster808 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.5.0 MIME-Version: 1.0 To: openembedded-core@lists.openembedded.org References: <1425481460-33631-1-git-send-email-tudor.florea@enea.com> <26724FB0BFCB3D4C91BDE184751AA3A428B78BAB@SESTOEX04.enea.se> In-Reply-To: <26724FB0BFCB3D4C91BDE184751AA3A428B78BAB@SESTOEX04.enea.se> Subject: Re: [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes module X-BeenThere: openembedded-core@lists.openembedded.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Patches and discussions about the oe-core layer List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 11 Mar 2015 13:42:12 -0000 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Tudor, I don't think aarch64 was supported in dizzy. If I find examples where it's support has been accept then I will consider letting this in. - Armin On 03/09/2015 05:24 PM, Tudor Florea wrote: > Ping. > >> -----Original Message----- >> From: Tudor Florea [mailto:tudor.florea@enea.com] >> Sent: Wednesday, March 04, 2015 17:04 >> To: openembedded-core@lists.openembedded.org >> Cc: Tudor Florea >> Subject: [dizzy] [PATCH 1/1] python: Add support for aarch64 for ctypes >> module >> >> Python have its own version of libffi used for ctypes module. >> libffi 3.0.10 contained in original source of Python-2.7.3 does not have >> support for aarch64 architecture. >> This is patch is backport support for aarch64 from libffi 3.1 >> --- >> .../python/python/ctypes-libffi-aarch64.patch | 22 + >> .../python/python/libffi-aarch64.patch | 1608 >> ++++++++++++++++++++ >> meta/recipes-devtools/python/python_2.7.3.bb | 2 + >> 3 files changed, 1632 insertions(+) >> create mode 100644 meta/recipes-devtools/python/python/ctypes-libffi- >> aarch64.patch >> create mode 100644 meta/recipes-devtools/python/python/libffi- >> aarch64.patch >> >> diff --git a/meta/recipes-devtools/python/python/ctypes-libffi- >> aarch64.patch b/meta/recipes-devtools/python/python/ctypes-libffi- >> aarch64.patch >> new file mode 100644 >> index 0000000..7349c7b >> --- /dev/null >> +++ b/meta/recipes-devtools/python/python/ctypes-libffi-aarch64.patch >> @@ -0,0 +1,22 @@ >> +Add missing fficonfig.py bits for aarch64 >> + >> +# HG changeset patch >> +# User Andreas Schwab >> +# Date 1367276434 -7200 >> +# Node ID 05e8999a3901b4853e60d6701510e9b3dd54a7f3 >> +# Parent 84cef4f1999ad9e362694cdac2f65f0981e3d5d0 >> + >> +Upstream-Status: Backport >> +Signed-off-by: Tudor Florea >> + >> +diff -r 84cef4f1999a -r 05e8999a3901 Modules/_ctypes/libffi/fficonfig.py.in >> +--- a/Modules/_ctypes/libffi/fficonfig.py.in Mon Apr 29 16:09:39 2013 - >> 0400 >> ++++ b/Modules/_ctypes/libffi/fficonfig.py.in Tue Apr 30 01:00:34 2013 >> +0200 >> +@@ -28,6 +28,7 @@ >> + 'PA': ['src/pa/linux.S', 'src/pa/ffi.c'], >> + 'PA_LINUX': ['src/pa/linux.S', 'src/pa/ffi.c'], >> + 'PA_HPUX': ['src/pa/hpux32.S', 'src/pa/ffi.c'], >> ++ 'AARCH64' : ['src/aarch64/ffi.c', 'src/aarch64/sysv.S'], >> + } >> + >> + ffi_sources += ffi_platforms['@TARGET@'] >> diff --git a/meta/recipes-devtools/python/python/libffi-aarch64.patch >> b/meta/recipes-devtools/python/python/libffi-aarch64.patch >> new file mode 100644 >> index 0000000..5581922 >> --- /dev/null >> +++ b/meta/recipes-devtools/python/python/libffi-aarch64.patch >> @@ -0,0 +1,1608 @@ >> +Add support for aarch64 for ctypes module >> + >> +Python have its own version of libffi used for ctypes module. >> +libffi 3.0.10 contained in original source of Python-2.7.3 does not have >> +support for aarch64 architecture. >> +This is patch is backport support for aarch64 from libffi 3.1 >> + >> +Upstream-Status: Backport >> +Signed-off-by: Tudor Florea >> + >> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/configure.ac Python- >> 2.7.3/Modules/_ctypes/libffi/configure.ac >> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/configure.ac 2015-02-27 >> 23:15:16.118393178 +0100 >> ++++ Python-2.7.3/Modules/_ctypes/libffi/configure.ac 2015-02-27 >> 23:51:03.351556903 +0100 >> +@@ -44,6 +44,10 @@ >> + >> + TARGETDIR="unknown" >> + case "$host" in >> ++ aarch64*-*-*) >> ++ TARGET=AARCH64; TARGETDIR=aarch64 >> ++ ;; >> ++ >> + alpha*-*-*) >> + TARGET=ALPHA; TARGETDIR=alpha; >> + # Support 128-bit long double, changeable via command-line switch. >> +@@ -195,6 +199,7 @@ >> + AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX) >> + AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = >> xPOWERPC_DARWIN) >> + AM_CONDITIONAL(POWERPC_FREEBSD, test x$TARGET = >> xPOWERPC_FREEBSD) >> ++AM_CONDITIONAL(AARCH64, test x$TARGET = xAARCH64) >> + AM_CONDITIONAL(ARM, test x$TARGET = xARM) >> + AM_CONDITIONAL(AVR32, test x$TARGET = xAVR32) >> + AM_CONDITIONAL(LIBFFI_CRIS, test x$TARGET = xLIBFFI_CRIS) >> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffi.c >> Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffi.c >> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffi.c 1970- >> 01-01 01:00:00.000000000 +0100 >> ++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffi.c 2014-04-25 >> 19:45:13.000000000 +0200 >> +@@ -0,0 +1,1168 @@ >> ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. >> ++ >> ++Permission is hereby granted, free of charge, to any person obtaining >> ++a copy of this software and associated documentation files (the >> ++``Software''), to deal in the Software without restriction, including >> ++without limitation the rights to use, copy, modify, merge, publish, >> ++distribute, sublicense, and/or sell copies of the Software, and to >> ++permit persons to whom the Software is furnished to do so, subject to >> ++the following conditions: >> ++ >> ++The above copyright notice and this permission notice shall be >> ++included in all copies or substantial portions of the Software. >> ++ >> ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, >> ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >> OF >> ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >> NONINFRINGEMENT. >> ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR >> ANY >> ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF >> CONTRACT, >> ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH >> THE >> ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ >> ++ >> ++#include >> ++ >> ++#include >> ++#include >> ++ >> ++#include >> ++ >> ++/* Stack alignment requirement in bytes */ >> ++#if defined (__APPLE__) >> ++#define AARCH64_STACK_ALIGN 1 >> ++#else >> ++#define AARCH64_STACK_ALIGN 16 >> ++#endif >> ++ >> ++#define N_X_ARG_REG 8 >> ++#define N_V_ARG_REG 8 >> ++ >> ++#define AARCH64_FFI_WITH_V (1 << AARCH64_FFI_WITH_V_BIT) >> ++ >> ++union _d >> ++{ >> ++ UINT64 d; >> ++ UINT32 s[2]; >> ++}; >> ++ >> ++struct call_context >> ++{ >> ++ UINT64 x [AARCH64_N_XREG]; >> ++ struct >> ++ { >> ++ union _d d[2]; >> ++ } v [AARCH64_N_VREG]; >> ++}; >> ++ >> ++#if defined (__clang__) && defined (__APPLE__) >> ++extern void >> ++sys_icache_invalidate (void *start, size_t len); >> ++#endif >> ++ >> ++static inline void >> ++ffi_clear_cache (void *start, void *end) >> ++{ >> ++#if defined (__clang__) && defined (__APPLE__) >> ++ sys_icache_invalidate (start, (char *)end - (char *)start); >> ++#elif defined (__GNUC__) >> ++ __builtin___clear_cache (start, end); >> ++#else >> ++#error "Missing builtin to flush instruction cache" >> ++#endif >> ++} >> ++ >> ++static void * >> ++get_x_addr (struct call_context *context, unsigned n) >> ++{ >> ++ return &context->x[n]; >> ++} >> ++ >> ++static void * >> ++get_s_addr (struct call_context *context, unsigned n) >> ++{ >> ++#if defined __AARCH64EB__ >> ++ return &context->v[n].d[1].s[1]; >> ++#else >> ++ return &context->v[n].d[0].s[0]; >> ++#endif >> ++} >> ++ >> ++static void * >> ++get_d_addr (struct call_context *context, unsigned n) >> ++{ >> ++#if defined __AARCH64EB__ >> ++ return &context->v[n].d[1]; >> ++#else >> ++ return &context->v[n].d[0]; >> ++#endif >> ++} >> ++ >> ++static void * >> ++get_v_addr (struct call_context *context, unsigned n) >> ++{ >> ++ return &context->v[n]; >> ++} >> ++ >> ++/* Return the memory location at which a basic type would reside >> ++ were it to have been stored in register n. */ >> ++ >> ++static void * >> ++get_basic_type_addr (unsigned short type, struct call_context *context, >> ++ unsigned n) >> ++{ >> ++ switch (type) >> ++ { >> ++ case FFI_TYPE_FLOAT: >> ++ return get_s_addr (context, n); >> ++ case FFI_TYPE_DOUBLE: >> ++ return get_d_addr (context, n); >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++ return get_v_addr (context, n); >> ++#endif >> ++ case FFI_TYPE_UINT8: >> ++ case FFI_TYPE_SINT8: >> ++ case FFI_TYPE_UINT16: >> ++ case FFI_TYPE_SINT16: >> ++ case FFI_TYPE_UINT32: >> ++ case FFI_TYPE_SINT32: >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_UINT64: >> ++ case FFI_TYPE_SINT64: >> ++ return get_x_addr (context, n); >> ++ case FFI_TYPE_VOID: >> ++ return NULL; >> ++ default: >> ++ FFI_ASSERT (0); >> ++ return NULL; >> ++ } >> ++} >> ++ >> ++/* Return the alignment width for each of the basic types. */ >> ++ >> ++static size_t >> ++get_basic_type_alignment (unsigned short type) >> ++{ >> ++ switch (type) >> ++ { >> ++ case FFI_TYPE_FLOAT: >> ++ case FFI_TYPE_DOUBLE: >> ++ return sizeof (UINT64); >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++ return sizeof (long double); >> ++#endif >> ++ case FFI_TYPE_UINT8: >> ++ case FFI_TYPE_SINT8: >> ++#if defined (__APPLE__) >> ++ return sizeof (UINT8); >> ++#endif >> ++ case FFI_TYPE_UINT16: >> ++ case FFI_TYPE_SINT16: >> ++#if defined (__APPLE__) >> ++ return sizeof (UINT16); >> ++#endif >> ++ case FFI_TYPE_UINT32: >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_SINT32: >> ++#if defined (__APPLE__) >> ++ return sizeof (UINT32); >> ++#endif >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_UINT64: >> ++ case FFI_TYPE_SINT64: >> ++ return sizeof (UINT64); >> ++ >> ++ default: >> ++ FFI_ASSERT (0); >> ++ return 0; >> ++ } >> ++} >> ++ >> ++/* Return the size in bytes for each of the basic types. */ >> ++ >> ++static size_t >> ++get_basic_type_size (unsigned short type) >> ++{ >> ++ switch (type) >> ++ { >> ++ case FFI_TYPE_FLOAT: >> ++ return sizeof (UINT32); >> ++ case FFI_TYPE_DOUBLE: >> ++ return sizeof (UINT64); >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++ return sizeof (long double); >> ++#endif >> ++ case FFI_TYPE_UINT8: >> ++ return sizeof (UINT8); >> ++ case FFI_TYPE_SINT8: >> ++ return sizeof (SINT8); >> ++ case FFI_TYPE_UINT16: >> ++ return sizeof (UINT16); >> ++ case FFI_TYPE_SINT16: >> ++ return sizeof (SINT16); >> ++ case FFI_TYPE_UINT32: >> ++ return sizeof (UINT32); >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_SINT32: >> ++ return sizeof (SINT32); >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_UINT64: >> ++ return sizeof (UINT64); >> ++ case FFI_TYPE_SINT64: >> ++ return sizeof (SINT64); >> ++ >> ++ default: >> ++ FFI_ASSERT (0); >> ++ return 0; >> ++ } >> ++} >> ++ >> ++extern void >> ++ffi_call_SYSV (unsigned (*)(struct call_context *context, unsigned char *, >> ++ extended_cif *), >> ++ struct call_context *context, >> ++ extended_cif *, >> ++ size_t, >> ++ void (*fn)(void)); >> ++ >> ++extern void >> ++ffi_closure_SYSV (ffi_closure *); >> ++ >> ++/* Test for an FFI floating point representation. */ >> ++ >> ++static unsigned >> ++is_floating_type (unsigned short type) >> ++{ >> ++ return (type == FFI_TYPE_FLOAT || type == FFI_TYPE_DOUBLE >> ++ || type == FFI_TYPE_LONGDOUBLE); >> ++} >> ++ >> ++/* Test for a homogeneous structure. */ >> ++ >> ++static unsigned short >> ++get_homogeneous_type (ffi_type *ty) >> ++{ >> ++ if (ty->type == FFI_TYPE_STRUCT && ty->elements) >> ++ { >> ++ unsigned i; >> ++ unsigned short candidate_type >> ++ = get_homogeneous_type (ty->elements[0]); >> ++ for (i =1; ty->elements[i]; i++) >> ++ { >> ++ unsigned short iteration_type = 0; >> ++ /* If we have a nested struct, we must find its homogeneous type. >> ++ If that fits with our candidate type, we are still >> ++ homogeneous. */ >> ++ if (ty->elements[i]->type == FFI_TYPE_STRUCT >> ++ && ty->elements[i]->elements) >> ++ { >> ++ iteration_type = get_homogeneous_type (ty->elements[i]); >> ++ } >> ++ else >> ++ { >> ++ iteration_type = ty->elements[i]->type; >> ++ } >> ++ >> ++ /* If we are not homogeneous, return FFI_TYPE_STRUCT. */ >> ++ if (candidate_type != iteration_type) >> ++ return FFI_TYPE_STRUCT; >> ++ } >> ++ return candidate_type; >> ++ } >> ++ >> ++ /* Base case, we have no more levels of nesting, so we >> ++ are a basic type, and so, trivially homogeneous in that type. */ >> ++ return ty->type; >> ++} >> ++ >> ++/* Determine the number of elements within a STRUCT. >> ++ >> ++ Note, we must handle nested structs. >> ++ >> ++ If ty is not a STRUCT this function will return 0. */ >> ++ >> ++static unsigned >> ++element_count (ffi_type *ty) >> ++{ >> ++ if (ty->type == FFI_TYPE_STRUCT && ty->elements) >> ++ { >> ++ unsigned n; >> ++ unsigned elems = 0; >> ++ for (n = 0; ty->elements[n]; n++) >> ++ { >> ++ if (ty->elements[n]->type == FFI_TYPE_STRUCT >> ++ && ty->elements[n]->elements) >> ++ elems += element_count (ty->elements[n]); >> ++ else >> ++ elems++; >> ++ } >> ++ return elems; >> ++ } >> ++ return 0; >> ++} >> ++ >> ++/* Test for a homogeneous floating point aggregate. >> ++ >> ++ A homogeneous floating point aggregate is a homogeneous aggregate of >> ++ a half- single- or double- precision floating point type with one >> ++ to four elements. Note that this includes nested structs of the >> ++ basic type. */ >> ++ >> ++static int >> ++is_hfa (ffi_type *ty) >> ++{ >> ++ if (ty->type == FFI_TYPE_STRUCT >> ++ && ty->elements[0] >> ++ && is_floating_type (get_homogeneous_type (ty))) >> ++ { >> ++ unsigned n = element_count (ty); >> ++ return n >= 1 && n <= 4; >> ++ } >> ++ return 0; >> ++} >> ++ >> ++/* Test if an ffi_type is a candidate for passing in a register. >> ++ >> ++ This test does not check that sufficient registers of the >> ++ appropriate class are actually available, merely that IFF >> ++ sufficient registers are available then the argument will be passed >> ++ in register(s). >> ++ >> ++ Note that an ffi_type that is deemed to be a register candidate >> ++ will always be returned in registers. >> ++ >> ++ Returns 1 if a register candidate else 0. */ >> ++ >> ++static int >> ++is_register_candidate (ffi_type *ty) >> ++{ >> ++ switch (ty->type) >> ++ { >> ++ case FFI_TYPE_VOID: >> ++ case FFI_TYPE_FLOAT: >> ++ case FFI_TYPE_DOUBLE: >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++#endif >> ++ case FFI_TYPE_UINT8: >> ++ case FFI_TYPE_UINT16: >> ++ case FFI_TYPE_UINT32: >> ++ case FFI_TYPE_UINT64: >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_SINT8: >> ++ case FFI_TYPE_SINT16: >> ++ case FFI_TYPE_SINT32: >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_SINT64: >> ++ return 1; >> ++ >> ++ case FFI_TYPE_STRUCT: >> ++ if (is_hfa (ty)) >> ++ { >> ++ return 1; >> ++ } >> ++ else if (ty->size > 16) >> ++ { >> ++ /* Too large. Will be replaced with a pointer to memory. The >> ++ pointer MAY be passed in a register, but the value will >> ++ not. This test specifically fails since the argument will >> ++ never be passed by value in registers. */ >> ++ return 0; >> ++ } >> ++ else >> ++ { >> ++ /* Might be passed in registers depending on the number of >> ++ registers required. */ >> ++ return (ty->size + 7) / 8 < N_X_ARG_REG; >> ++ } >> ++ break; >> ++ >> ++ default: >> ++ FFI_ASSERT (0); >> ++ break; >> ++ } >> ++ >> ++ return 0; >> ++} >> ++ >> ++/* Test if an ffi_type argument or result is a candidate for a vector >> ++ register. */ >> ++ >> ++static int >> ++is_v_register_candidate (ffi_type *ty) >> ++{ >> ++ return is_floating_type (ty->type) >> ++ || (ty->type == FFI_TYPE_STRUCT && is_hfa (ty)); >> ++} >> ++ >> ++/* Representation of the procedure call argument marshalling >> ++ state. >> ++ >> ++ The terse state variable names match the names used in the AARCH64 >> ++ PCS. */ >> ++ >> ++struct arg_state >> ++{ >> ++ unsigned ngrn; /* Next general-purpose register number. */ >> ++ unsigned nsrn; /* Next vector register number. */ >> ++ size_t nsaa; /* Next stack offset. */ >> ++ >> ++#if defined (__APPLE__) >> ++ unsigned allocating_variadic; >> ++#endif >> ++}; >> ++ >> ++/* Initialize a procedure call argument marshalling state. */ >> ++static void >> ++arg_init (struct arg_state *state, size_t call_frame_size) >> ++{ >> ++ state->ngrn = 0; >> ++ state->nsrn = 0; >> ++ state->nsaa = 0; >> ++ >> ++#if defined (__APPLE__) >> ++ state->allocating_variadic = 0; >> ++#endif >> ++} >> ++ >> ++/* Return the number of available consecutive core argument >> ++ registers. */ >> ++ >> ++static unsigned >> ++available_x (struct arg_state *state) >> ++{ >> ++ return N_X_ARG_REG - state->ngrn; >> ++} >> ++ >> ++/* Return the number of available consecutive vector argument >> ++ registers. */ >> ++ >> ++static unsigned >> ++available_v (struct arg_state *state) >> ++{ >> ++ return N_V_ARG_REG - state->nsrn; >> ++} >> ++ >> ++static void * >> ++allocate_to_x (struct call_context *context, struct arg_state *state) >> ++{ >> ++ FFI_ASSERT (state->ngrn < N_X_ARG_REG); >> ++ return get_x_addr (context, (state->ngrn)++); >> ++} >> ++ >> ++static void * >> ++allocate_to_s (struct call_context *context, struct arg_state *state) >> ++{ >> ++ FFI_ASSERT (state->nsrn < N_V_ARG_REG); >> ++ return get_s_addr (context, (state->nsrn)++); >> ++} >> ++ >> ++static void * >> ++allocate_to_d (struct call_context *context, struct arg_state *state) >> ++{ >> ++ FFI_ASSERT (state->nsrn < N_V_ARG_REG); >> ++ return get_d_addr (context, (state->nsrn)++); >> ++} >> ++ >> ++static void * >> ++allocate_to_v (struct call_context *context, struct arg_state *state) >> ++{ >> ++ FFI_ASSERT (state->nsrn < N_V_ARG_REG); >> ++ return get_v_addr (context, (state->nsrn)++); >> ++} >> ++ >> ++/* Allocate an aligned slot on the stack and return a pointer to it. */ >> ++static void * >> ++allocate_to_stack (struct arg_state *state, void *stack, size_t alignment, >> ++ size_t size) >> ++{ >> ++ void *allocation; >> ++ >> ++ /* Round up the NSAA to the larger of 8 or the natural >> ++ alignment of the argument's type. */ >> ++ state->nsaa = ALIGN (state->nsaa, alignment); >> ++ state->nsaa = ALIGN (state->nsaa, alignment); >> ++#if defined (__APPLE__) >> ++ if (state->allocating_variadic) >> ++ state->nsaa = ALIGN (state->nsaa, 8); >> ++#else >> ++ state->nsaa = ALIGN (state->nsaa, 8); >> ++#endif >> ++ >> ++ allocation = stack + state->nsaa; >> ++ >> ++ state->nsaa += size; >> ++ return allocation; >> ++} >> ++ >> ++static void >> ++copy_basic_type (void *dest, void *source, unsigned short type) >> ++{ >> ++ /* This is necessary to ensure that basic types are copied >> ++ sign extended to 64-bits as libffi expects. */ >> ++ switch (type) >> ++ { >> ++ case FFI_TYPE_FLOAT: >> ++ *(float *) dest = *(float *) source; >> ++ break; >> ++ case FFI_TYPE_DOUBLE: >> ++ *(double *) dest = *(double *) source; >> ++ break; >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++ *(long double *) dest = *(long double *) source; >> ++ break; >> ++#endif >> ++ case FFI_TYPE_UINT8: >> ++ *(ffi_arg *) dest = *(UINT8 *) source; >> ++ break; >> ++ case FFI_TYPE_SINT8: >> ++ *(ffi_sarg *) dest = *(SINT8 *) source; >> ++ break; >> ++ case FFI_TYPE_UINT16: >> ++ *(ffi_arg *) dest = *(UINT16 *) source; >> ++ break; >> ++ case FFI_TYPE_SINT16: >> ++ *(ffi_sarg *) dest = *(SINT16 *) source; >> ++ break; >> ++ case FFI_TYPE_UINT32: >> ++ *(ffi_arg *) dest = *(UINT32 *) source; >> ++ break; >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_SINT32: >> ++ *(ffi_sarg *) dest = *(SINT32 *) source; >> ++ break; >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_UINT64: >> ++ *(ffi_arg *) dest = *(UINT64 *) source; >> ++ break; >> ++ case FFI_TYPE_SINT64: >> ++ *(ffi_sarg *) dest = *(SINT64 *) source; >> ++ break; >> ++ case FFI_TYPE_VOID: >> ++ break; >> ++ >> ++ default: >> ++ FFI_ASSERT (0); >> ++ } >> ++} >> ++ >> ++static void >> ++copy_hfa_to_reg_or_stack (void *memory, >> ++ ffi_type *ty, >> ++ struct call_context *context, >> ++ unsigned char *stack, >> ++ struct arg_state *state) >> ++{ >> ++ unsigned elems = element_count (ty); >> ++ if (available_v (state) < elems) >> ++ { >> ++ /* There are insufficient V registers. Further V register allocations >> ++ are prevented, the NSAA is adjusted (by allocate_to_stack ()) >> ++ and the argument is copied to memory at the adjusted NSAA. */ >> ++ state->nsrn = N_V_ARG_REG; >> ++ memcpy (allocate_to_stack (state, stack, ty->alignment, ty->size), >> ++ memory, >> ++ ty->size); >> ++ } >> ++ else >> ++ { >> ++ int i; >> ++ unsigned short type = get_homogeneous_type (ty); >> ++ for (i = 0; i < elems; i++) >> ++ { >> ++ void *reg = allocate_to_v (context, state); >> ++ copy_basic_type (reg, memory, type); >> ++ memory += get_basic_type_size (type); >> ++ } >> ++ } >> ++} >> ++ >> ++/* Either allocate an appropriate register for the argument type, or if >> ++ none are available, allocate a stack slot and return a pointer >> ++ to the allocated space. */ >> ++ >> ++static void * >> ++allocate_to_register_or_stack (struct call_context *context, >> ++ unsigned char *stack, >> ++ struct arg_state *state, >> ++ unsigned short type) >> ++{ >> ++ size_t alignment = get_basic_type_alignment (type); >> ++ size_t size = alignment; >> ++ switch (type) >> ++ { >> ++ case FFI_TYPE_FLOAT: >> ++ /* This is the only case for which the allocated stack size >> ++ should not match the alignment of the type. */ >> ++ size = sizeof (UINT32); >> ++ /* Fall through. */ >> ++ case FFI_TYPE_DOUBLE: >> ++ if (state->nsrn < N_V_ARG_REG) >> ++ return allocate_to_d (context, state); >> ++ state->nsrn = N_V_ARG_REG; >> ++ break; >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++ if (state->nsrn < N_V_ARG_REG) >> ++ return allocate_to_v (context, state); >> ++ state->nsrn = N_V_ARG_REG; >> ++ break; >> ++#endif >> ++ case FFI_TYPE_UINT8: >> ++ case FFI_TYPE_SINT8: >> ++ case FFI_TYPE_UINT16: >> ++ case FFI_TYPE_SINT16: >> ++ case FFI_TYPE_UINT32: >> ++ case FFI_TYPE_SINT32: >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_UINT64: >> ++ case FFI_TYPE_SINT64: >> ++ if (state->ngrn < N_X_ARG_REG) >> ++ return allocate_to_x (context, state); >> ++ state->ngrn = N_X_ARG_REG; >> ++ break; >> ++ default: >> ++ FFI_ASSERT (0); >> ++ } >> ++ >> ++ return allocate_to_stack (state, stack, alignment, size); >> ++} >> ++ >> ++/* Copy a value to an appropriate register, or if none are >> ++ available, to the stack. */ >> ++ >> ++static void >> ++copy_to_register_or_stack (struct call_context *context, >> ++ unsigned char *stack, >> ++ struct arg_state *state, >> ++ void *value, >> ++ unsigned short type) >> ++{ >> ++ copy_basic_type ( >> ++ allocate_to_register_or_stack (context, stack, state, type), >> ++ value, >> ++ type); >> ++} >> ++ >> ++/* Marshall the arguments from FFI representation to procedure call >> ++ context and stack. */ >> ++ >> ++static unsigned >> ++aarch64_prep_args (struct call_context *context, unsigned char *stack, >> ++ extended_cif *ecif) >> ++{ >> ++ int i; >> ++ struct arg_state state; >> ++ >> ++ arg_init (&state, ALIGN(ecif->cif->bytes, 16)); >> ++ >> ++ for (i = 0; i < ecif->cif->nargs; i++) >> ++ { >> ++ ffi_type *ty = ecif->cif->arg_types[i]; >> ++ switch (ty->type) >> ++ { >> ++ case FFI_TYPE_VOID: >> ++ FFI_ASSERT (0); >> ++ break; >> ++ >> ++ /* If the argument is a basic type the argument is allocated to an >> ++ appropriate register, or if none are available, to the stack. */ >> ++ case FFI_TYPE_FLOAT: >> ++ case FFI_TYPE_DOUBLE: >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++#endif >> ++ case FFI_TYPE_UINT8: >> ++ case FFI_TYPE_SINT8: >> ++ case FFI_TYPE_UINT16: >> ++ case FFI_TYPE_SINT16: >> ++ case FFI_TYPE_UINT32: >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_SINT32: >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_UINT64: >> ++ case FFI_TYPE_SINT64: >> ++ copy_to_register_or_stack (context, stack, &state, >> ++ ecif->avalue[i], ty->type); >> ++ break; >> ++ >> ++ case FFI_TYPE_STRUCT: >> ++ if (is_hfa (ty)) >> ++ { >> ++ copy_hfa_to_reg_or_stack (ecif->avalue[i], ty, context, >> ++ stack, &state); >> ++ } >> ++ else if (ty->size > 16) >> ++ { >> ++ /* If the argument is a composite type that is larger than 16 >> ++ bytes, then the argument has been copied to memory, and >> ++ the argument is replaced by a pointer to the copy. */ >> ++ >> ++ copy_to_register_or_stack (context, stack, &state, >> ++ &(ecif->avalue[i]), >> FFI_TYPE_POINTER); >> ++ } >> ++ else if (available_x (&state) >= (ty->size + 7) / 8) >> ++ { >> ++ /* If the argument is a composite type and the size in >> ++ double-words is not more than the number of available >> ++ X registers, then the argument is copied into consecutive >> ++ X registers. */ >> ++ int j; >> ++ for (j = 0; j < (ty->size + 7) / 8; j++) >> ++ { >> ++ memcpy (allocate_to_x (context, &state), >> ++ &(((UINT64 *) ecif->avalue[i])[j]), >> ++ sizeof (UINT64)); >> ++ } >> ++ } >> ++ else >> ++ { >> ++ /* Otherwise, there are insufficient X registers. Further X >> ++ register allocations are prevented, the NSAA is adjusted >> ++ (by allocate_to_stack ()) and the argument is copied to >> ++ memory at the adjusted NSAA. */ >> ++ state.ngrn = N_X_ARG_REG; >> ++ >> ++ memcpy (allocate_to_stack (&state, stack, ty->alignment, >> ++ ty->size), ecif->avalue + i, ty->size); >> ++ } >> ++ break; >> ++ >> ++ default: >> ++ FFI_ASSERT (0); >> ++ break; >> ++ } >> ++ >> ++#if defined (__APPLE__) >> ++ if (i + 1 == ecif->cif->aarch64_nfixedargs) >> ++ { >> ++ state.ngrn = N_X_ARG_REG; >> ++ state.nsrn = N_V_ARG_REG; >> ++ >> ++ state.allocating_variadic = 1; >> ++ } >> ++#endif >> ++ } >> ++ >> ++ return ecif->cif->aarch64_flags; >> ++} >> ++ >> ++ffi_status >> ++ffi_prep_cif_machdep (ffi_cif *cif) >> ++{ >> ++ /* Round the stack up to a multiple of the stack alignment requirement. >> */ >> ++ cif->bytes = >> ++ (cif->bytes + (AARCH64_STACK_ALIGN - 1)) & ~ >> (AARCH64_STACK_ALIGN - 1); >> ++ >> ++ /* Initialize our flags. We are interested if this CIF will touch a >> ++ vector register, if so we will enable context save and load to >> ++ those registers, otherwise not. This is intended to be friendly >> ++ to lazy float context switching in the kernel. */ >> ++ cif->aarch64_flags = 0; >> ++ >> ++ if (is_v_register_candidate (cif->rtype)) >> ++ { >> ++ cif->aarch64_flags |= AARCH64_FFI_WITH_V; >> ++ } >> ++ else >> ++ { >> ++ int i; >> ++ for (i = 0; i < cif->nargs; i++) >> ++ if (is_v_register_candidate (cif->arg_types[i])) >> ++ { >> ++ cif->aarch64_flags |= AARCH64_FFI_WITH_V; >> ++ break; >> ++ } >> ++ } >> ++ >> ++ return FFI_OK; >> ++} >> ++ >> ++#if defined (__APPLE__) >> ++ >> ++/* Perform Apple-specific cif processing for variadic calls */ >> ++ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, >> ++ unsigned int nfixedargs, >> ++ unsigned int ntotalargs) >> ++{ >> ++ cif->aarch64_nfixedargs = nfixedargs; >> ++ >> ++ return ffi_prep_cif_machdep(cif); >> ++} >> ++ >> ++#endif >> ++ >> ++/* Call a function with the provided arguments and capture the return >> ++ value. */ >> ++void >> ++ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) >> ++{ >> ++ extended_cif ecif; >> ++ >> ++ ecif.cif = cif; >> ++ ecif.avalue = avalue; >> ++ ecif.rvalue = rvalue; >> ++ >> ++ switch (cif->abi) >> ++ { >> ++ case FFI_SYSV: >> ++ { >> ++ struct call_context context; >> ++ size_t stack_bytes; >> ++ >> ++ /* Figure out the total amount of stack space we need, the >> ++ above call frame space needs to be 16 bytes aligned to >> ++ ensure correct alignment of the first object inserted in >> ++ that space hence the ALIGN applied to cif->bytes.*/ >> ++ stack_bytes = ALIGN(cif->bytes, 16); >> ++ >> ++ memset (&context, 0, sizeof (context)); >> ++ if (is_register_candidate (cif->rtype)) >> ++ { >> ++ ffi_call_SYSV (aarch64_prep_args, &context, &ecif, stack_bytes, fn); >> ++ switch (cif->rtype->type) >> ++ { >> ++ case FFI_TYPE_VOID: >> ++ case FFI_TYPE_FLOAT: >> ++ case FFI_TYPE_DOUBLE: >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++#endif >> ++ case FFI_TYPE_UINT8: >> ++ case FFI_TYPE_SINT8: >> ++ case FFI_TYPE_UINT16: >> ++ case FFI_TYPE_SINT16: >> ++ case FFI_TYPE_UINT32: >> ++ case FFI_TYPE_SINT32: >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_UINT64: >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_SINT64: >> ++ { >> ++ void *addr = get_basic_type_addr (cif->rtype->type, >> ++ &context, 0); >> ++ copy_basic_type (rvalue, addr, cif->rtype->type); >> ++ break; >> ++ } >> ++ >> ++ case FFI_TYPE_STRUCT: >> ++ if (is_hfa (cif->rtype)) >> ++ { >> ++ int j; >> ++ unsigned short type = get_homogeneous_type (cif- >>> rtype); >> ++ unsigned elems = element_count (cif->rtype); >> ++ for (j = 0; j < elems; j++) >> ++ { >> ++ void *reg = get_basic_type_addr (type, &context, j); >> ++ copy_basic_type (rvalue, reg, type); >> ++ rvalue += get_basic_type_size (type); >> ++ } >> ++ } >> ++ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG) >> ++ { >> ++ size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)); >> ++ memcpy (rvalue, get_x_addr (&context, 0), size); >> ++ } >> ++ else >> ++ { >> ++ FFI_ASSERT (0); >> ++ } >> ++ break; >> ++ >> ++ default: >> ++ FFI_ASSERT (0); >> ++ break; >> ++ } >> ++ } >> ++ else >> ++ { >> ++ memcpy (get_x_addr (&context, 8), &rvalue, sizeof (UINT64)); >> ++ ffi_call_SYSV (aarch64_prep_args, &context, &ecif, >> ++ stack_bytes, fn); >> ++ } >> ++ break; >> ++ } >> ++ >> ++ default: >> ++ FFI_ASSERT (0); >> ++ break; >> ++ } >> ++} >> ++ >> ++static unsigned char trampoline [] = >> ++{ 0x70, 0x00, 0x00, 0x58, /* ldr x16, 1f */ >> ++ 0x91, 0x00, 0x00, 0x10, /* adr x17, 2f */ >> ++ 0x00, 0x02, 0x1f, 0xd6 /* br x16 */ >> ++}; >> ++ >> ++/* Build a trampoline. */ >> ++ >> ++#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,FLAGS) >> \ >> ++ ({unsigned char *__tramp = (unsigned char*)(TRAMP); >> \ >> ++ UINT64 __fun = (UINT64)(FUN); \ >> ++ UINT64 __ctx = (UINT64)(CTX); \ >> ++ UINT64 __flags = (UINT64)(FLAGS); >> \ >> ++ memcpy (__tramp, trampoline, sizeof (trampoline)); >> \ >> ++ memcpy (__tramp + 12, &__fun, sizeof (__fun)); \ >> ++ memcpy (__tramp + 20, &__ctx, sizeof (__ctx)); \ >> ++ memcpy (__tramp + 28, &__flags, sizeof (__flags)); >> \ >> ++ ffi_clear_cache(__tramp, __tramp + FFI_TRAMPOLINE_SIZE); >> \ >> ++ }) >> ++ >> ++ffi_status >> ++ffi_prep_closure_loc (ffi_closure* closure, >> ++ ffi_cif* cif, >> ++ void (*fun)(ffi_cif*,void*,void**,void*), >> ++ void *user_data, >> ++ void *codeloc) >> ++{ >> ++ if (cif->abi != FFI_SYSV) >> ++ return FFI_BAD_ABI; >> ++ >> ++ FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV, codeloc, >> ++ cif->aarch64_flags); >> ++ >> ++ closure->cif = cif; >> ++ closure->user_data = user_data; >> ++ closure->fun = fun; >> ++ >> ++ return FFI_OK; >> ++} >> ++ >> ++/* Primary handler to setup and invoke a function within a closure. >> ++ >> ++ A closure when invoked enters via the assembler wrapper >> ++ ffi_closure_SYSV(). The wrapper allocates a call context on the >> ++ stack, saves the interesting registers (from the perspective of >> ++ the calling convention) into the context then passes control to >> ++ ffi_closure_SYSV_inner() passing the saved context and a pointer to >> ++ the stack at the point ffi_closure_SYSV() was invoked. >> ++ >> ++ On the return path the assembler wrapper will reload call context >> ++ registers. >> ++ >> ++ ffi_closure_SYSV_inner() marshalls the call context into ffi value >> ++ descriptors, invokes the wrapped function, then marshalls the return >> ++ value back into the call context. */ >> ++ >> ++void FFI_HIDDEN >> ++ffi_closure_SYSV_inner (ffi_closure *closure, struct call_context *context, >> ++ void *stack) >> ++{ >> ++ ffi_cif *cif = closure->cif; >> ++ void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); >> ++ void *rvalue = NULL; >> ++ int i; >> ++ struct arg_state state; >> ++ >> ++ arg_init (&state, ALIGN(cif->bytes, 16)); >> ++ >> ++ for (i = 0; i < cif->nargs; i++) >> ++ { >> ++ ffi_type *ty = cif->arg_types[i]; >> ++ >> ++ switch (ty->type) >> ++ { >> ++ case FFI_TYPE_VOID: >> ++ FFI_ASSERT (0); >> ++ break; >> ++ >> ++ case FFI_TYPE_UINT8: >> ++ case FFI_TYPE_SINT8: >> ++ case FFI_TYPE_UINT16: >> ++ case FFI_TYPE_SINT16: >> ++ case FFI_TYPE_UINT32: >> ++ case FFI_TYPE_SINT32: >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_UINT64: >> ++ case FFI_TYPE_SINT64: >> ++ case FFI_TYPE_FLOAT: >> ++ case FFI_TYPE_DOUBLE: >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++ avalue[i] = allocate_to_register_or_stack (context, stack, >> ++ &state, ty->type); >> ++ break; >> ++#endif >> ++ >> ++ case FFI_TYPE_STRUCT: >> ++ if (is_hfa (ty)) >> ++ { >> ++ unsigned n = element_count (ty); >> ++ if (available_v (&state) < n) >> ++ { >> ++ state.nsrn = N_V_ARG_REG; >> ++ avalue[i] = allocate_to_stack (&state, stack, ty->alignment, >> ++ ty->size); >> ++ } >> ++ else >> ++ { >> ++ switch (get_homogeneous_type (ty)) >> ++ { >> ++ case FFI_TYPE_FLOAT: >> ++ { >> ++ /* Eeek! We need a pointer to the structure, >> ++ however the homogeneous float elements are >> ++ being passed in individual S registers, >> ++ therefore the structure is not represented as >> ++ a contiguous sequence of bytes in our saved >> ++ register context. We need to fake up a copy >> ++ of the structure laid out in memory >> ++ correctly. The fake can be tossed once the >> ++ closure function has returned hence alloca() >> ++ is sufficient. */ >> ++ int j; >> ++ UINT32 *p = avalue[i] = alloca (ty->size); >> ++ for (j = 0; j < element_count (ty); j++) >> ++ memcpy (&p[j], >> ++ allocate_to_s (context, &state), >> ++ sizeof (*p)); >> ++ break; >> ++ } >> ++ >> ++ case FFI_TYPE_DOUBLE: >> ++ { >> ++ /* Eeek! We need a pointer to the structure, >> ++ however the homogeneous float elements are >> ++ being passed in individual S registers, >> ++ therefore the structure is not represented as >> ++ a contiguous sequence of bytes in our saved >> ++ register context. We need to fake up a copy >> ++ of the structure laid out in memory >> ++ correctly. The fake can be tossed once the >> ++ closure function has returned hence alloca() >> ++ is sufficient. */ >> ++ int j; >> ++ UINT64 *p = avalue[i] = alloca (ty->size); >> ++ for (j = 0; j < element_count (ty); j++) >> ++ memcpy (&p[j], >> ++ allocate_to_d (context, &state), >> ++ sizeof (*p)); >> ++ break; >> ++ } >> ++ >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++ memcpy (&avalue[i], >> ++ allocate_to_v (context, &state), >> ++ sizeof (*avalue)); >> ++ break; >> ++#endif >> ++ >> ++ default: >> ++ FFI_ASSERT (0); >> ++ break; >> ++ } >> ++ } >> ++ } >> ++ else if (ty->size > 16) >> ++ { >> ++ /* Replace Composite type of size greater than 16 with a >> ++ pointer. */ >> ++ memcpy (&avalue[i], >> ++ allocate_to_register_or_stack (context, stack, >> ++ &state, >> FFI_TYPE_POINTER), >> ++ sizeof (avalue[i])); >> ++ } >> ++ else if (available_x (&state) >= (ty->size + 7) / 8) >> ++ { >> ++ avalue[i] = get_x_addr (context, state.ngrn); >> ++ state.ngrn += (ty->size + 7) / 8; >> ++ } >> ++ else >> ++ { >> ++ state.ngrn = N_X_ARG_REG; >> ++ >> ++ avalue[i] = allocate_to_stack (&state, stack, ty->alignment, >> ++ ty->size); >> ++ } >> ++ break; >> ++ >> ++ default: >> ++ FFI_ASSERT (0); >> ++ break; >> ++ } >> ++ } >> ++ >> ++ /* Figure out where the return value will be passed, either in >> ++ registers or in a memory block allocated by the caller and passed >> ++ in x8. */ >> ++ >> ++ if (is_register_candidate (cif->rtype)) >> ++ { >> ++ /* Register candidates are *always* returned in registers. */ >> ++ >> ++ /* Allocate a scratchpad for the return value, we will let the >> ++ callee scrible the result into the scratch pad then move the >> ++ contents into the appropriate return value location for the >> ++ call convention. */ >> ++ rvalue = alloca (cif->rtype->size); >> ++ (closure->fun) (cif, rvalue, avalue, closure->user_data); >> ++ >> ++ /* Copy the return value into the call context so that it is returned >> ++ as expected to our caller. */ >> ++ switch (cif->rtype->type) >> ++ { >> ++ case FFI_TYPE_VOID: >> ++ break; >> ++ >> ++ case FFI_TYPE_UINT8: >> ++ case FFI_TYPE_UINT16: >> ++ case FFI_TYPE_UINT32: >> ++ case FFI_TYPE_POINTER: >> ++ case FFI_TYPE_UINT64: >> ++ case FFI_TYPE_SINT8: >> ++ case FFI_TYPE_SINT16: >> ++ case FFI_TYPE_INT: >> ++ case FFI_TYPE_SINT32: >> ++ case FFI_TYPE_SINT64: >> ++ case FFI_TYPE_FLOAT: >> ++ case FFI_TYPE_DOUBLE: >> ++#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE >> ++ case FFI_TYPE_LONGDOUBLE: >> ++#endif >> ++ { >> ++ void *addr = get_basic_type_addr (cif->rtype->type, context, 0); >> ++ copy_basic_type (addr, rvalue, cif->rtype->type); >> ++ break; >> ++ } >> ++ case FFI_TYPE_STRUCT: >> ++ if (is_hfa (cif->rtype)) >> ++ { >> ++ int j; >> ++ unsigned short type = get_homogeneous_type (cif->rtype); >> ++ unsigned elems = element_count (cif->rtype); >> ++ for (j = 0; j < elems; j++) >> ++ { >> ++ void *reg = get_basic_type_addr (type, context, j); >> ++ copy_basic_type (reg, rvalue, type); >> ++ rvalue += get_basic_type_size (type); >> ++ } >> ++ } >> ++ else if ((cif->rtype->size + 7) / 8 < N_X_ARG_REG) >> ++ { >> ++ size_t size = ALIGN (cif->rtype->size, sizeof (UINT64)) ; >> ++ memcpy (get_x_addr (context, 0), rvalue, size); >> ++ } >> ++ else >> ++ { >> ++ FFI_ASSERT (0); >> ++ } >> ++ break; >> ++ default: >> ++ FFI_ASSERT (0); >> ++ break; >> ++ } >> ++ } >> ++ else >> ++ { >> ++ memcpy (&rvalue, get_x_addr (context, 8), sizeof (UINT64)); >> ++ (closure->fun) (cif, rvalue, avalue, closure->user_data); >> ++ } >> ++} >> ++ >> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffitarget.h >> Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffitarget.h >> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/ffitarget.h 1970- >> 01-01 01:00:00.000000000 +0100 >> ++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/ffitarget.h 2014- >> 04-25 19:45:13.000000000 +0200 >> +@@ -0,0 +1,63 @@ >> ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. >> ++ >> ++Permission is hereby granted, free of charge, to any person obtaining >> ++a copy of this software and associated documentation files (the >> ++``Software''), to deal in the Software without restriction, including >> ++without limitation the rights to use, copy, modify, merge, publish, >> ++distribute, sublicense, and/or sell copies of the Software, and to >> ++permit persons to whom the Software is furnished to do so, subject to >> ++the following conditions: >> ++ >> ++The above copyright notice and this permission notice shall be >> ++included in all copies or substantial portions of the Software. >> ++ >> ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, >> ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >> OF >> ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >> NONINFRINGEMENT. >> ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR >> ANY >> ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF >> CONTRACT, >> ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH >> THE >> ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ >> ++ >> ++#ifndef LIBFFI_TARGET_H >> ++#define LIBFFI_TARGET_H >> ++ >> ++#ifndef LIBFFI_H >> ++#error "Please do not include ffitarget.h directly into your source. Use >> ffi.h instead." >> ++#endif >> ++ >> ++#ifndef LIBFFI_ASM >> ++typedef unsigned long ffi_arg; >> ++typedef signed long ffi_sarg; >> ++ >> ++typedef enum ffi_abi >> ++ { >> ++ FFI_FIRST_ABI = 0, >> ++ FFI_SYSV, >> ++ FFI_LAST_ABI, >> ++ FFI_DEFAULT_ABI = FFI_SYSV >> ++ } ffi_abi; >> ++#endif >> ++ >> ++/* ---- Definitions for closures ----------------------------------------- */ >> ++ >> ++#define FFI_CLOSURES 1 >> ++#define FFI_TRAMPOLINE_SIZE 36 >> ++#define FFI_NATIVE_RAW_API 0 >> ++ >> ++/* ---- Internal ---- */ >> ++ >> ++#if defined (__APPLE__) >> ++#define FFI_TARGET_SPECIFIC_VARIADIC >> ++#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags; unsigned >> aarch64_nfixedargs >> ++#else >> ++#define FFI_EXTRA_CIF_FIELDS unsigned aarch64_flags >> ++#endif >> ++ >> ++#define AARCH64_FFI_WITH_V_BIT 0 >> ++ >> ++#define AARCH64_N_XREG 32 >> ++#define AARCH64_N_VREG 32 >> ++#define AARCH64_CALL_CONTEXT_SIZE (AARCH64_N_XREG * 8 + >> AARCH64_N_VREG * 16) >> ++ >> ++#endif >> +diff -ruN Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/sysv.S >> Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/sysv.S >> +--- Python-2.7.3.orig/Modules/_ctypes/libffi/src/aarch64/sysv.S 1970- >> 01-01 01:00:00.000000000 +0100 >> ++++ Python-2.7.3/Modules/_ctypes/libffi/src/aarch64/sysv.S 2014-04-25 >> 19:45:13.000000000 +0200 >> +@@ -0,0 +1,333 @@ >> ++/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. >> ++ >> ++Permission is hereby granted, free of charge, to any person obtaining >> ++a copy of this software and associated documentation files (the >> ++``Software''), to deal in the Software without restriction, including >> ++without limitation the rights to use, copy, modify, merge, publish, >> ++distribute, sublicense, and/or sell copies of the Software, and to >> ++permit persons to whom the Software is furnished to do so, subject to >> ++the following conditions: >> ++ >> ++The above copyright notice and this permission notice shall be >> ++included in all copies or substantial portions of the Software. >> ++ >> ++THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, >> ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES >> OF >> ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND >> NONINFRINGEMENT. >> ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR >> ANY >> ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF >> CONTRACT, >> ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH >> THE >> ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ >> ++ >> ++#define LIBFFI_ASM >> ++#include >> ++#include >> ++ >> ++#ifdef HAVE_MACHINE_ASM_H >> ++#include >> ++#else >> ++#ifdef __USER_LABEL_PREFIX__ >> ++#define CONCAT1(a, b) CONCAT2(a, b) >> ++#define CONCAT2(a, b) a ## b >> ++ >> ++/* Use the right prefix for global labels. */ >> ++#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) >> ++#else >> ++#define CNAME(x) x >> ++#endif >> ++#endif >> ++ >> ++#define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off >> ++#define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off >> ++#define cfi_restore(reg) .cfi_restore reg >> ++#define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg >> ++ >> ++ .text >> ++ .globl CNAME(ffi_call_SYSV) >> ++#ifdef __ELF__ >> ++ .type CNAME(ffi_call_SYSV), #function >> ++#endif >> ++#ifdef __APPLE__ >> ++ .align 2 >> ++#endif >> ++ >> ++/* ffi_call_SYSV() >> ++ >> ++ Create a stack frame, setup an argument context, call the callee >> ++ and extract the result. >> ++ >> ++ The maximum required argument stack size is provided, >> ++ ffi_call_SYSV() allocates that stack space then calls the >> ++ prepare_fn to populate register context and stack. The >> ++ argument passing registers are loaded from the register >> ++ context and the callee called, on return the register passing >> ++ register are saved back to the context. Our caller will >> ++ extract the return value from the final state of the saved >> ++ register context. >> ++ >> ++ Prototype: >> ++ >> ++ extern unsigned >> ++ ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *, >> ++ extended_cif *), >> ++ struct call_context *context, >> ++ extended_cif *, >> ++ size_t required_stack_size, >> ++ void (*fn)(void)); >> ++ >> ++ Therefore on entry we have: >> ++ >> ++ x0 prepare_fn >> ++ x1 &context >> ++ x2 &ecif >> ++ x3 bytes >> ++ x4 fn >> ++ >> ++ This function uses the following stack frame layout: >> ++ >> ++ == >> ++ saved x30(lr) >> ++ x29(fp)-> saved x29(fp) >> ++ saved x24 >> ++ saved x23 >> ++ saved x22 >> ++ sp' -> saved x21 >> ++ ... >> ++ sp -> (constructed callee stack arguments) >> ++ == >> ++ >> ++ Voila! */ >> ++ >> ++#define ffi_call_SYSV_FS (8 * 4) >> ++ >> ++ .cfi_startproc >> ++CNAME(ffi_call_SYSV): >> ++ stp x29, x30, [sp, #-16]! >> ++ cfi_adjust_cfa_offset (16) >> ++ cfi_rel_offset (x29, 0) >> ++ cfi_rel_offset (x30, 8) >> ++ >> ++ mov x29, sp >> ++ cfi_def_cfa_register (x29) >> ++ sub sp, sp, #ffi_call_SYSV_FS >> ++ >> ++ stp x21, x22, [sp, #0] >> ++ cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS) >> ++ cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS) >> ++ >> ++ stp x23, x24, [sp, #16] >> ++ cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS) >> ++ cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS) >> ++ >> ++ mov x21, x1 >> ++ mov x22, x2 >> ++ mov x24, x4 >> ++ >> ++ /* Allocate the stack space for the actual arguments, many >> ++ arguments will be passed in registers, but we assume >> ++ worst case and allocate sufficient stack for ALL of >> ++ the arguments. */ >> ++ sub sp, sp, x3 >> ++ >> ++ /* unsigned (*prepare_fn) (struct call_context *context, >> ++ unsigned char *stack, extended_cif *ecif); >> ++ */ >> ++ mov x23, x0 >> ++ mov x0, x1 >> ++ mov x1, sp >> ++ /* x2 already in place */ >> ++ blr x23 >> ++ >> ++ /* Preserve the flags returned. */ >> ++ mov x23, x0 >> ++ >> ++ /* Figure out if we should touch the vector registers. */ >> ++ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f >> ++ >> ++ /* Load the vector argument passing registers. */ >> ++ ldp q0, q1, [x21, #8*32 + 0] >> ++ ldp q2, q3, [x21, #8*32 + 32] >> ++ ldp q4, q5, [x21, #8*32 + 64] >> ++ ldp q6, q7, [x21, #8*32 + 96] >> ++1: >> ++ /* Load the core argument passing registers. */ >> ++ ldp x0, x1, [x21, #0] >> ++ ldp x2, x3, [x21, #16] >> ++ ldp x4, x5, [x21, #32] >> ++ ldp x6, x7, [x21, #48] >> ++ >> ++ /* Don't forget x8 which may be holding the address of a return >> buffer. >> ++ */ >> ++ ldr x8, [x21, #8*8] >> ++ >> ++ blr x24 >> ++ >> ++ /* Save the core argument passing registers. */ >> ++ stp x0, x1, [x21, #0] >> ++ stp x2, x3, [x21, #16] >> ++ stp x4, x5, [x21, #32] >> ++ stp x6, x7, [x21, #48] >> ++ >> ++ /* Note nothing useful ever comes back in x8! */ >> ++ >> ++ /* Figure out if we should touch the vector registers. */ >> ++ tbz x23, #AARCH64_FFI_WITH_V_BIT, 1f >> ++ >> ++ /* Save the vector argument passing registers. */ >> ++ stp q0, q1, [x21, #8*32 + 0] >> ++ stp q2, q3, [x21, #8*32 + 32] >> ++ stp q4, q5, [x21, #8*32 + 64] >> ++ stp q6, q7, [x21, #8*32 + 96] >> ++1: >> ++ /* All done, unwind our stack frame. */ >> ++ ldp x21, x22, [x29, # - ffi_call_SYSV_FS] >> ++ cfi_restore (x21) >> ++ cfi_restore (x22) >> ++ >> ++ ldp x23, x24, [x29, # - ffi_call_SYSV_FS + 16] >> ++ cfi_restore (x23) >> ++ cfi_restore (x24) >> ++ >> ++ mov sp, x29 >> ++ cfi_def_cfa_register (sp) >> ++ >> ++ ldp x29, x30, [sp], #16 >> ++ cfi_adjust_cfa_offset (-16) >> ++ cfi_restore (x29) >> ++ cfi_restore (x30) >> ++ >> ++ ret >> ++ >> ++ .cfi_endproc >> ++#ifdef __ELF__ >> ++ .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV) >> ++#endif >> ++ >> ++#define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE) >> ++ >> ++/* ffi_closure_SYSV >> ++ >> ++ Closure invocation glue. This is the low level code invoked directly by >> ++ the closure trampoline to setup and call a closure. >> ++ >> ++ On entry x17 points to a struct trampoline_data, x16 has been clobbered >> ++ all other registers are preserved. >> ++ >> ++ We allocate a call context and save the argument passing registers, >> ++ then invoked the generic C ffi_closure_SYSV_inner() function to do all >> ++ the real work, on return we load the result passing registers back from >> ++ the call context. >> ++ >> ++ On entry >> ++ >> ++ extern void >> ++ ffi_closure_SYSV (struct trampoline_data *); >> ++ >> ++ struct trampoline_data >> ++ { >> ++ UINT64 *ffi_closure; >> ++ UINT64 flags; >> ++ }; >> ++ >> ++ This function uses the following stack frame layout: >> ++ >> ++ == >> ++ saved x30(lr) >> ++ x29(fp)-> saved x29(fp) >> ++ saved x22 >> ++ saved x21 >> ++ ... >> ++ sp -> call_context >> ++ == >> ++ >> ++ Voila! */ >> ++ >> ++ .text >> ++ .globl CNAME(ffi_closure_SYSV) >> ++#ifdef __APPLE__ >> ++ .align 2 >> ++#endif >> ++ .cfi_startproc >> ++CNAME(ffi_closure_SYSV): >> ++ stp x29, x30, [sp, #-16]! >> ++ cfi_adjust_cfa_offset (16) >> ++ cfi_rel_offset (x29, 0) >> ++ cfi_rel_offset (x30, 8) >> ++ >> ++ mov x29, sp >> ++ cfi_def_cfa_register (x29) >> ++ >> ++ sub sp, sp, #ffi_closure_SYSV_FS >> ++ >> ++ stp x21, x22, [x29, #-16] >> ++ cfi_rel_offset (x21, -16) >> ++ cfi_rel_offset (x22, -8) >> ++ >> ++ /* Load x21 with &call_context. */ >> ++ mov x21, sp >> ++ /* Preserve our struct trampoline_data * */ >> ++ mov x22, x17 >> ++ >> ++ /* Save the rest of the argument passing registers. */ >> ++ stp x0, x1, [x21, #0] >> ++ stp x2, x3, [x21, #16] >> ++ stp x4, x5, [x21, #32] >> ++ stp x6, x7, [x21, #48] >> ++ /* Don't forget we may have been given a result scratch pad address. >> ++ */ >> ++ str x8, [x21, #64] >> ++ >> ++ /* Figure out if we should touch the vector registers. */ >> ++ ldr x0, [x22, #8] >> ++ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f >> ++ >> ++ /* Save the argument passing vector registers. */ >> ++ stp q0, q1, [x21, #8*32 + 0] >> ++ stp q2, q3, [x21, #8*32 + 32] >> ++ stp q4, q5, [x21, #8*32 + 64] >> ++ stp q6, q7, [x21, #8*32 + 96] >> ++1: >> ++ /* Load &ffi_closure.. */ >> ++ ldr x0, [x22, #0] >> ++ mov x1, x21 >> ++ /* Compute the location of the stack at the point that the >> ++ trampoline was called. */ >> ++ add x2, x29, #16 >> ++ >> ++ bl CNAME(ffi_closure_SYSV_inner) >> ++ >> ++ /* Figure out if we should touch the vector registers. */ >> ++ ldr x0, [x22, #8] >> ++ tbz x0, #AARCH64_FFI_WITH_V_BIT, 1f >> ++ >> ++ /* Load the result passing vector registers. */ >> ++ ldp q0, q1, [x21, #8*32 + 0] >> ++ ldp q2, q3, [x21, #8*32 + 32] >> ++ ldp q4, q5, [x21, #8*32 + 64] >> ++ ldp q6, q7, [x21, #8*32 + 96] >> ++1: >> ++ /* Load the result passing core registers. */ >> ++ ldp x0, x1, [x21, #0] >> ++ ldp x2, x3, [x21, #16] >> ++ ldp x4, x5, [x21, #32] >> ++ ldp x6, x7, [x21, #48] >> ++ /* Note nothing useful is returned in x8. */ >> ++ >> ++ /* We are done, unwind our frame. */ >> ++ ldp x21, x22, [x29, #-16] >> ++ cfi_restore (x21) >> ++ cfi_restore (x22) >> ++ >> ++ mov sp, x29 >> ++ cfi_def_cfa_register (sp) >> ++ >> ++ ldp x29, x30, [sp], #16 >> ++ cfi_adjust_cfa_offset (-16) >> ++ cfi_restore (x29) >> ++ cfi_restore (x30) >> ++ >> ++ ret >> ++ .cfi_endproc >> ++#ifdef __ELF__ >> ++ .size CNAME(ffi_closure_SYSV), .-CNAME(ffi_closure_SYSV) >> ++#endif >> diff --git a/meta/recipes-devtools/python/python_2.7.3.bb b/meta/recipes- >> devtools/python/python_2.7.3.bb >> index cbe8d7f..de1f57f 100644 >> --- a/meta/recipes-devtools/python/python_2.7.3.bb >> +++ b/meta/recipes-devtools/python/python_2.7.3.bb >> @@ -40,6 +40,8 @@ SRC_URI += "\ >> file://posix_close.patch \ >> file://python-2.7.3-CVE-2014-7185.patch \ >> file://python2.7.3-nossl3.patch \ >> + file://ctypes-libffi-aarch64.patch \ >> + file://libffi-aarch64.patch \ >> " >> >> S = "${WORKDIR}/Python-${PV}" >> -- >> 1.9.1 >