Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ endif()
# The C flags are final here: an indirect tail call under -mregparm loses its
# pointer argument unless sibling calls are off. m68k cross builds only.
include("${CMAKE_SOURCE_DIR}/cmake/check-regparm-sibcall.cmake")
# And the callbacks a driver from another build calls stay on the stack.
include("${CMAKE_SOURCE_DIR}/cmake/check-anxs2ext-abi.cmake")

# ---------------------------------------------------------------- options ---

Expand Down
69 changes: 69 additions & 0 deletions cmake/check-anxs2ext-abi.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# The anxs2ext.h callbacks take their arguments on the stack.
#
# include(check-anxs2ext-abi) -- at configure, m68k cross builds only
#
# RxDirect, RxFilled and TxFlags are called by a driver built separately from
# the library, often from another release, and every release before -mregparm
# pushed their arguments. d6b6a7e7 left the typedefs unpinned: its library
# read a0/d0 for what a 144042c driver had pushed, RxDirect answered an address
# made of its own code bytes, and on a PiStorm32 A1200 neither card came up.
# This compiles a call through each typedef with the tree's flags and stops
# the configure unless the caller pops what it pushed: 8, 16 and 4 bytes.
#
# SPDX-License-Identifier: MIT

if(NOT CMAKE_CROSSCOMPILING)
return()
endif()

set(_s2x_dir "${CMAKE_BINARY_DIR}/check-anxs2ext-abi")
file(MAKE_DIRECTORY "${_s2x_dir}")
file(WRITE "${_s2x_dir}/probe.c" [=[
#include <aminetxduo/anxs2ext.h>
UBYTE *probe_rx_direct(AnxdS2RxDirect f, APTR io, ULONG len)
{
return f(io, len) + 1;
}
ULONG probe_rx_filled(AnxdS2RxFilled f, APTR io, ULONG len, ULONG sum, UBYTE fl)
{
f(io, len, sum, fl);
return len + 1;
}
UBYTE probe_tx_flags(AnxdS2TxFlags f, APTR io)
{
return (UBYTE)(f(io) + 1);
}
]=])

# The flags the objects are built with, less LTO: -S has to produce assembly.
separate_arguments(_s2x_flags UNIX_COMMAND
"${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_RELEASE}")
list(REMOVE_ITEM _s2x_flags -flto)

execute_process(
COMMAND "${CMAKE_C_COMPILER}" ${_s2x_flags}
"-I${CMAKE_SOURCE_DIR}/include" -S
-o "${_s2x_dir}/probe.s" "${_s2x_dir}/probe.c"
RESULT_VARIABLE _s2x_rc
ERROR_VARIABLE _s2x_err)
if(NOT _s2x_rc EQUAL 0)
message(FATAL_ERROR "check-anxs2ext-abi: the probe did not compile:\n${_s2x_err}")
endif()

file(READ "${_s2x_dir}/probe.s" _s2x_asm)

foreach(_s2x_pair "rx_direct;8" "rx_filled;16" "tx_flags;4")
list(GET _s2x_pair 0 _s2x_fn)
list(GET _s2x_pair 1 _s2x_n)
string(REGEX MATCH "_probe_${_s2x_fn}:[^:]*" _s2x_body "${_s2x_asm}")
if(NOT _s2x_body MATCHES
"jsr[^\n]*\n(.*\n)?[ \t]*(addq\\.[wl][ \t]+#${_s2x_n},%?sp|add\\.[wl][ \t]+#${_s2x_n},%?sp|lea[ \t]+\\(${_s2x_n},%?sp\\),%?sp|lea[ \t]+${_s2x_n}\\(%?sp\\),%?sp|lea[ \t]+%?sp@\\(${_s2x_n}\\),%?sp)")
message(FATAL_ERROR
"check-anxs2ext-abi: a call through AnxdS2* (${_s2x_fn}) does not "
"pass its arguments on the stack under -mregparm=${AMINETXDUO_REGPARM}; "
"a driver from another build would read the wrong registers. "
"See ${_s2x_dir}/probe.s")
endif()
endforeach()

message(STATUS "check-anxs2ext-abi: driver callbacks pass on the stack (regparm ${AMINETXDUO_REGPARM})")
4 changes: 4 additions & 0 deletions cmake/toolchain-m68k-amigaos.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,10 @@ string(REPLACE ";" " " AMIGA_ARCH_FLAGS_STR "${AMIGA_ARCH_FLAGS}")
# whatever -mregparm says;
# - user-supplied hooks (loghook.c, errno.c, netmonitor.c) pin a0/a1/a2, so a
# caller compiled the ordinary way is still called correctly;
# - the aminetxduo/anxs2ext.h callbacks a driver calls into the library
# (RxDirect, RxFilled, TxFlags) carry __stdargs, because the driver may be
# from another build. MISSED when the option landed: a 144042c anxnet.device
# under a d6b6a7e7 library moved no frames. cmake/check-anxs2ext-abi.cmake;
# - the hand-written routines in src/net68k and src/crypto68k read the stack,
# and every C declaration of one carries AMIGA_ASM_ARGS
# (__attribute__((__stkparm__))); see include/aminetxduo/asm_abi.h.
Expand Down
22 changes: 18 additions & 4 deletions include/aminetxduo/anxs2ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,24 @@
wire together. Negotiated as ANXD_S2F_TX_MORE. */
#define ANXD_S2_TXF_MORE 0x40

typedef UBYTE *(*AnxdS2RxDirect)(APTR ios2_data, ULONG len);
typedef VOID (*AnxdS2RxFilled)(APTR ios2_data, ULONG len, ULONG sum,
UBYTE flags);
typedef UBYTE (*AnxdS2TxFlags)(APTR ios2_data);
/*
* The callbacks below cross between separately built binaries, a driver from
* one release calling a library from another, so their arguments go on the
* stack whatever the compiler was told. A GCC for AmigaOS predefines
* __stdargs as that pin; a compiler without it already passes on the stack.
* Unpinned under -mregparm, a library read a0/d0 for what an older driver had
* pushed, and RxDirect answered an address made of its own code bytes.
*/
#if defined(__GNUC__) && defined(__stdargs)
#define ANXD_S2_STDARGS __stdargs
#else
#define ANXD_S2_STDARGS
#endif

typedef ANXD_S2_STDARGS UBYTE *(*AnxdS2RxDirect)(APTR ios2_data, ULONG len);
typedef ANXD_S2_STDARGS VOID (*AnxdS2RxFilled)(APTR ios2_data, ULONG len,
ULONG sum, UBYTE flags);
typedef ANXD_S2_STDARGS UBYTE (*AnxdS2TxFlags)(APTR ios2_data);

/*
* ONE VERSIONED NEGOTIATION TAG.
Expand Down
5 changes: 3 additions & 2 deletions src/sana2/sana2_copy.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ BOOL ami_sana2_copy_from_buff(register APTR to __asm("a0"),
* A slot that cannot answer safely declines and the device takes the staging
* path. Interrupt level, copybuff.doc constraints.
*/
UBYTE *ami_sana2_rx_direct(APTR ios2_data, ULONG len)
AMIGA_ASM_ARGS UBYTE *ami_sana2_rx_direct(APTR ios2_data, ULONG len)
{
AmiRxSlot *slot = (AmiRxSlot *)ios2_data;

Expand All @@ -564,7 +564,8 @@ UBYTE *ami_sana2_rx_direct(APTR ios2_data, ULONG len)
* verifier walks the frame); VERIFIED is kept whole for the
* reader, which only sees them from a device that accepted RX_VERIFIED.
*/
VOID ami_sana2_rx_filled(APTR ios2_data, ULONG len, ULONG sum, UBYTE flags)
AMIGA_ASM_ARGS VOID ami_sana2_rx_filled(APTR ios2_data, ULONG len, ULONG sum,
UBYTE flags)
{
AmiRxSlot *slot = (AmiRxSlot *)ios2_data;

Expand Down
11 changes: 7 additions & 4 deletions src/sana2/sana2_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "aminetxduo/config.h"
#include "aminetxduo/compat.h"
#include "aminetxduo/anxs2ext.h"
#include "aminetxduo/asm_abi.h"

#include "sana2_device.h"

Expand Down Expand Up @@ -978,9 +979,11 @@ struct AmiSana2If

/* ------------------------------------------------------------- internals */

/* sana2_copy.c, called by the device in m68k register convention. */
UBYTE *ami_sana2_rx_direct(APTR ios2_data, ULONG len);
VOID ami_sana2_rx_filled(APTR ios2_data, ULONG len, ULONG sum, UBYTE summed);
/* sana2_copy.c, called by the device with its arguments on the stack
(aminetxduo/anxs2ext.h). */
AMIGA_ASM_ARGS UBYTE *ami_sana2_rx_direct(APTR ios2_data, ULONG len);
AMIGA_ASM_ARGS VOID ami_sana2_rx_filled(APTR ios2_data, ULONG len, ULONG sum,
UBYTE summed);

/* Bytes a known vendor driver's card holds from the wire, by name; 0 for
any other (sana2_device.c). */
Expand All @@ -994,7 +997,7 @@ BOOL ami_sana2_copy_to_buff(register APTR to __asm("a0"),
register APTR from __asm("a1"),
register ULONG len __asm("d0"));
BOOL ami_sana2_tx_pseudo_sum(NX_PACKET *pkt);
UBYTE ami_sana2_tx_flags(APTR ios2_data);
AMIGA_ASM_ARGS UBYTE ami_sana2_tx_flags(APTR ios2_data);
#ifdef AMINETXDUO_TX_RUN
/* The flush request came back on tx_port: the device queued it rather than
finishing it inside BeginIO() (sana2_tx.c). */
Expand Down
2 changes: 1 addition & 1 deletion src/sana2/sana2_txmeta.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/* A driver may call this while advancing a queued write from interrupt
context. ios2_Data is the opener-owned slot for every request we submit,
so the entire callback is deliberately one guarded byte load. */
UBYTE ami_sana2_tx_flags(APTR ios2_data)
AMIGA_ASM_ARGS UBYTE ami_sana2_tx_flags(APTR ios2_data)
{
const AmiTxSlot *slot = (const AmiTxSlot *)ios2_data;

Expand Down
Loading