mirror of
https://github.com/SDL-Hercules-390/hyperion.git
synced 2026-07-26 02:29:51 +02:00
916 lines
40 KiB
C
916 lines
40 KiB
C
/* HMACROS.H (C) Copyright Roger Bowler, 1999-2012 */
|
|
/* Hercules macros... */
|
|
/* */
|
|
/* Released under "The Q Public License Version 1" */
|
|
/* (http://www.hercules-390.org/herclic.html) as modifications to */
|
|
/* Hercules. */
|
|
|
|
// This header auto-#included by 'hercules.h'...
|
|
//
|
|
// The <config.h> header and other required headers are
|
|
// presumed to have already been #included ahead of it...
|
|
|
|
|
|
#ifndef _HMACROS_H
|
|
#define _HMACROS_H
|
|
|
|
#include "hercules.h"
|
|
#include "dbgtrace.h"
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* UNREACHABLE_CODE code that should NEVER be reached */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#ifdef _MSVC_
|
|
#define UNREACHABLE_CODE(ret) __assume(0)
|
|
#else
|
|
#define UNREACHABLE_CODE(ret) BREAK_INTO_DEBUGGER(); ret
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Define INLINE attributes by compiler */
|
|
/*-------------------------------------------------------------------*/
|
|
#if !defined(INLINE)
|
|
#if defined(__GNUC__)
|
|
#define INLINE __inline
|
|
#else
|
|
#define INLINE __inline
|
|
#endif
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Define THREAD_LOCAL attributes by compiler */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#if !defined(THREAD_LOCAL)
|
|
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
|
|
&& !defined __STDC_NO_THREADS__
|
|
#define THREAD_LOCAL _Thread_local
|
|
#elif defined(_MSC_VER)
|
|
#define THREAD_LOCAL __declspec(thread)
|
|
#elif defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER)
|
|
#define THREAD_LOCAL __thread
|
|
#else
|
|
#define THREAD_LOCAL /* thread_local */
|
|
#endif
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Round a value 'x' up to the next 'b' boundary */
|
|
/*-------------------------------------------------------------------*/
|
|
#define ROUND_UP(x,b) ((x)?((((x)+((b)-1))/(b))*(b)):(b))
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Ensure start-end range stays within limits */
|
|
/*-------------------------------------------------------------------*/
|
|
#define LIMIT_RANGE( _start, _end, _limit ) \
|
|
do { \
|
|
if ((_end) > (_limit) && ((_end) - (_limit) + 1) > (_start)) \
|
|
(_end) = ((_start) + (_limit) - 1); \
|
|
} while(0)
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Define min/max macros */
|
|
/*-------------------------------------------------------------------*/
|
|
#if !defined(min)
|
|
#define min(_x, _y) ((_x) < (_y) ? (_x) : (_y))
|
|
#endif
|
|
#if !defined(max)
|
|
#define max(_x, _y) ((_x) > (_y) ? (_x) : (_y))
|
|
#endif
|
|
#if !defined(MIN)
|
|
#define MIN(_x,_y) min((_x),(_y))
|
|
#endif
|
|
#if !defined(MAX)
|
|
#define MAX(_x,_y) max((_x),(_y))
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* MINMAX ensures var x remains within range y to z */
|
|
/*-------------------------------------------------------------------*/
|
|
#if !defined(MINMAX)
|
|
#define MINMAX(_x,_y,_z) ((_x) = MIN(MAX((_x),(_y)),(_z)))
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* some handy array/struct macros... */
|
|
/*-------------------------------------------------------------------*/
|
|
#ifndef _countof
|
|
#define _countof(x) ( sizeof(x) / sizeof(x[0]) )
|
|
#endif
|
|
#ifndef arraysize
|
|
#define arraysize(x) _countof(x)
|
|
#endif
|
|
#ifndef sizeof_member
|
|
#define sizeof_member(_struct,_member) sizeof(((_struct*)0)->_member)
|
|
#endif
|
|
#ifndef offsetof
|
|
#define offsetof(_struct,_member) (size_t)&(((_struct*)0)->_member)
|
|
#endif
|
|
|
|
#define BIT_ARRAY_BYT( _b ) ( (_b / 8))
|
|
#define BIT_ARRAY_MSK( _b ) (0x80 >> (_b % 8))
|
|
|
|
#define BIT_ARRAY_SET( _a, _b ) (_a[BIT_ARRAY_BYT(_b)] |= BIT_ARRAY_MSK(_b))
|
|
#define BIT_ARRAY_CLR( _a, _b ) (_a[BIT_ARRAY_BYT(_b)] &= ~BIT_ARRAY_MSK(_b))
|
|
|
|
#define IS_BIT_ARRAY_SET( _a, _b ) (_a[BIT_ARRAY_BYT(_b)] & BIT_ARRAY_MSK(_b))
|
|
#define IS_BIT_ARRAY_CLR( _a, _b ) (!IS_BIT_ARRAY_SET(_a,_b))
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* CASSERT macro a compile time assertion check */
|
|
/*-------------------------------------------------------------------*/
|
|
/**
|
|
* Validates at compile time whether condition is true without
|
|
* generating code. It can be used at any point in a source file
|
|
* where typedefs are legal.
|
|
*
|
|
* On success, compilation proceeds normally.
|
|
*
|
|
* Sample usage:
|
|
*
|
|
* CASSERT( sizeof( struct foo ) == 76, demo_c );
|
|
*
|
|
* On failure, attempts to typedef an array type of negative size
|
|
* resulting in a compiler error message that might look something
|
|
* like the following:
|
|
*
|
|
* demo.c:32: error: size of array 'assertion_failed_demo_c_32' is negative
|
|
*
|
|
* The offending line itself will look something like this:
|
|
*
|
|
* typedef assertion_failed_demo_c_32[-1]
|
|
*
|
|
* where demo_c is the content of the second parameter which should
|
|
* typically be related in some obvious way to the containing file
|
|
* name, 32 is the line number in the file on which the assertion
|
|
* appears, and -1 is the result of a calculation based on the cond
|
|
* failing.
|
|
*
|
|
* \param cond The predicate to test. It should evaluate
|
|
* to something which can be coerced into a
|
|
* normal C boolean.
|
|
*
|
|
* \param file A sequence of legal identifier characters
|
|
* that should uniquely identify the source
|
|
* file where the CASSERT statement appears.
|
|
*/
|
|
#if !defined( CASSERT )
|
|
#define CASSERT( cond, file ) _CASSERT_LINE( cond, __LINE__, file )
|
|
#define _CASSERT_PASTE( a, b ) a ## b
|
|
#define _CASSERT_LINE( cond, line, file ) \
|
|
typedef char _CASSERT_PASTE( assertion_failed_ ## file, line )[ 2 * !!(cond) - 1 ]
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* compiler optimization hints (for performance) */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#undef likely
|
|
#undef unlikely
|
|
|
|
#if defined(_MSVC_) && !defined( __clang__ )
|
|
|
|
#define likely(_c) ( (_c) ? ( __assume((_c)), 1 ) : 0 )
|
|
#define unlikely(_c) ( (_c) ? 1 : ( __assume(!(_c)), 0 ) )
|
|
|
|
#else // !_MSVC_
|
|
|
|
#if __GNUC__ >= 3
|
|
#define likely(_c) __builtin_expect((_c),1)
|
|
#define unlikely(_c) __builtin_expect((_c),0)
|
|
#else
|
|
#define likely(_c) (_c)
|
|
#define unlikely(_c) (_c)
|
|
#endif
|
|
|
|
#endif // _MSVC_
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* _MSVC_ portability macros */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/* PROGRAMMING NOTE: the following 'tape' portability macros are
|
|
only for physical (SCSI) tape devices, not emulated aws files */
|
|
|
|
#ifdef _MSVC_
|
|
#define open_tape w32_open_tape
|
|
#define read_tape w32_read_tape
|
|
#define write_tape w32_write_tape
|
|
#define ioctl_tape w32_ioctl_tape
|
|
#define close_tape w32_close_tape
|
|
#else
|
|
#define open_tape open
|
|
#define read_tape read
|
|
#define write_tape write
|
|
#define ioctl_tape ioctl
|
|
#define close_tape close
|
|
#endif
|
|
|
|
#ifdef _MSVC_
|
|
#define create_pipe(a) socketpair(AF_INET,SOCK_STREAM,IPPROTO_IP,a)
|
|
#define read_pipe(f,b,n) recv(f,b,n,0)
|
|
#define write_pipe(f,b,n) send(f,b,(int)n,0)
|
|
#define close_pipe(f) closesocket(f)
|
|
#else
|
|
#define create_pipe(f) pipe(f)
|
|
#define read_pipe(f,b,n) read(f,b,n)
|
|
#define write_pipe(f,b,n) write(f,b,n)
|
|
#define close_pipe(f) close(f)
|
|
#endif
|
|
|
|
#ifdef _MSVC_
|
|
#define socket w32_socket
|
|
#define accept w32_accept
|
|
/* Now defined in hsocket.h
|
|
int read_socket(int fd, char *ptr, int nbytes);
|
|
int write_socket(int fd, const char *ptr, int nbytes);
|
|
*/
|
|
#define close_socket w32_close_socket
|
|
#define hif_nametoindex w32_if_nametoindex
|
|
#define hinet_ntop w32_inet_ntop
|
|
#define hinet_pton w32_inet_pton
|
|
#else
|
|
/* Now defined in hsocket.h
|
|
int read_socket(int fd, char *ptr, int nbytes);
|
|
int write_socket(int fd, const char *ptr, int nbytes);
|
|
*/
|
|
#define close_socket(f) close(f)
|
|
#define hif_nametoindex if_nametoindex
|
|
#define hinet_ntop inet_ntop
|
|
#define hinet_pton inet_pton
|
|
#endif
|
|
|
|
#ifdef _MSVC_
|
|
#undef FD_SET
|
|
#undef FD_ISSET
|
|
#define FD_SET w32_FD_SET
|
|
#define FD_ISSET w32_FD_ISSET
|
|
#define select(n,r,w,e,t) w32_select((n),(r),(w),(e),(t),__FILE__,__LINE__)
|
|
#define pselect(n,r,w,e,t,m) w32_pselect((n),(r),(w),(e),(t),(m),__FILE__,__LINE__)
|
|
#define poll(p,n,t) WSAPoll((p),(n),(t))
|
|
#define fdopen w32_fdopen
|
|
#define fwrite w32_fwrite
|
|
#define fprintf w32_fprintf
|
|
#define fclose w32_fclose
|
|
#define basename w32_basename
|
|
#define dirname w32_dirname
|
|
#ifndef strcasestr
|
|
#define strcasestr w32_strcasestr
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _MSVC_
|
|
#define fdatasync _commit
|
|
#define atoll _atoi64
|
|
#else /* !_MSVC_ */
|
|
#if !defined(HAVE_FDATASYNC_SUPPORTED)
|
|
#ifdef HAVE_FSYNC
|
|
#define fdatasync fsync
|
|
#else
|
|
#error Required 'fdatasync' function is missing and alternate 'fsync' function also missing
|
|
#endif
|
|
#endif
|
|
#define atoll(s) strtoll(s,NULL,0)
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Portable macro for copying 'va_list' variable arguments variable */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
// ZZ FIXME: this should probably be handled in configure.ac...
|
|
|
|
#if !defined( va_copy )
|
|
#if defined( __va_copy )
|
|
#define va_copy __va_copy
|
|
#elif defined( _MSVC_ )
|
|
#define va_copy(to,from) (to) = (from)
|
|
#else
|
|
#define va_copy(to,from) memcpy((to),(from),sizeof(va_list))
|
|
#endif
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Handle newer RUSAGE_THREAD definition for older Linux levels */
|
|
/* before 2.6.4 along with *nix systems not supporting... */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
// ZZ FIXME: this should probably be handled in configure.ac...
|
|
|
|
#if !defined(RUSAGE_THREAD) && !defined(_MSVC_)
|
|
#define RUSAGE_THREAD thread_id()
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Some handy memory/string comparison macros */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#if defined( _MSVC_ )
|
|
#define strcasecmp _stricmp
|
|
#define strncasecmp _strnicmp
|
|
#endif
|
|
|
|
#define mem_eq(_a,_b,_n) (!memcmp(_a,_b,_n))
|
|
#define mem_ne(_a,_b,_n) ( memcmp(_a,_b,_n))
|
|
|
|
// PROGRAMMING NOTE: see also header "extstring.h"
|
|
|
|
#define str_eq(_a,_b) (!strcmp(_a,_b))
|
|
#define str_ne(_a,_b) ( strcmp(_a,_b))
|
|
|
|
#define str_eq_n(_a,_b,_n) (!strncmp(_a,_b,_n))
|
|
#define str_ne_n(_a,_b,_n) ( strncmp(_a,_b,_n))
|
|
|
|
#define str_caseless_eq(_a,_b) (!strcasecmp(_a,_b))
|
|
#define str_caseless_ne(_a,_b) ( strcasecmp(_a,_b))
|
|
|
|
#define str_caseless_eq_n(_a,_b,_n) (!strncasecmp(_a,_b,_n))
|
|
#define str_caseless_ne_n(_a,_b,_n) ( strncasecmp(_a,_b,_n))
|
|
|
|
#define UPPER_ARGV_0( _argv ) do {if (_argv && _argv[0]) strupper( _argv[0], _argv[0] );} while (0)
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Large File Support portability */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#ifdef _MSVC_
|
|
/* "Native" 64-bit Large File Support */
|
|
#define off_t __int64
|
|
#define ftruncate _chsize_s
|
|
#define ftell _ftelli64
|
|
#define fseek _fseeki64
|
|
#define lseek _lseeki64
|
|
#define fstat _fstati64
|
|
#define stat _stati64
|
|
#elif defined(_LFS_LARGEFILE) || ( defined(SIZEOF_OFF_T) && SIZEOF_OFF_T > 4 )
|
|
/* Native 64-bit Large File Support */
|
|
#if defined(HAVE_FSEEKO)
|
|
#define ftell ftello
|
|
#define fseek fseeko
|
|
#else
|
|
#if defined(SIZEOF_LONG) && SIZEOF_LONG <= 4
|
|
WARNING( "fseek/ftell use offset arguments of insufficient size" )
|
|
#endif
|
|
#endif
|
|
#elif defined(_LFS64_LARGEFILE)
|
|
/* Transitional 64-bit Large File Support */
|
|
#define off_t off64_t
|
|
#define ftruncate ftruncate64
|
|
#define ftell ftello64
|
|
#define fseek fseeko64
|
|
#define lseek lseek64
|
|
#define fstat fstat64
|
|
#define stat stat64
|
|
#else // !defined(_LFS_LARGEFILE) && !defined(_LFS64_LARGEFILE) && (!defined(SIZEOF_OFF_T) || SIZEOF_OFF_T <= 4)
|
|
/* No 64-bit Large File Support at all */
|
|
WARNING( "Large File Support missing" )
|
|
#endif
|
|
// Hercules low-level file open...
|
|
// PROGRAMMING NOTE: the "##" preceding "__VA_ARGS__" is required for compat-
|
|
// ibility with gcc/MSVC compilers and must not be removed
|
|
#ifdef _MSVC_
|
|
#define HOPEN(_p,_o,...) w32_hopen ((_p),(_o), ## __VA_ARGS__)
|
|
#else
|
|
#define HOPEN(_p,_o,...) hopen ((_p),(_o), ## __VA_ARGS__)
|
|
#endif
|
|
|
|
#define MAX_OFFSET_T ((off_t)(ULLONG_MAX))
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Macro for command parsing with variable length */
|
|
/*-------------------------------------------------------------------*/
|
|
#define CMD(str,cmd,min) ( strcaseabbrev(#cmd,str,min) )
|
|
|
|
#define NCMP(_lvar,_rvar,_svar) ( !memcmp( _lvar, _rvar, _svar ) )
|
|
#define SNCMP(_lvar,_rvar,_svar) ( !strncasecmp( _lvar, _rvar, _svar ) )
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Debugging / Tracing macros. */
|
|
/*-------------------------------------------------------------------*/
|
|
#define MLVL( _lvl) \
|
|
(sysblk.msglvl & (MLVL_ ## _lvl))
|
|
|
|
/* Opcode routing table function pointer */
|
|
typedef void (ATTR_REGPARM(2)*FUNC)();
|
|
|
|
/* Program Interrupt function pointer */
|
|
typedef void (ATTR_REGPARM(2) *pi_func) (REGS *regs, int pcode);
|
|
|
|
/* trace_br function */
|
|
typedef U32 (*s390_trace_br_func) (int amode, U32 ia, REGS *regs);
|
|
typedef U64 (*z900_trace_br_func) (int amode, U64 ia, REGS *regs);
|
|
|
|
/* qsort comparison function typedef */
|
|
typedef int CMPFUNC(const void*, const void*);
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* CPU state related macros and constants */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
/* Definitions for CPU state */
|
|
#define CPUSTATE_STARTED 1 /* CPU is started */
|
|
#define CPUSTATE_STOPPING 2 /* CPU is stopping */
|
|
#define CPUSTATE_STOPPED 3 /* CPU is stopped */
|
|
|
|
#define IS_CPU_ONLINE(_cpu) \
|
|
(sysblk.regs[(_cpu)] != NULL)
|
|
|
|
#define HOST( _regs ) (_regs)->hostregs
|
|
#define GUEST( _regs ) (_regs)->guestregs
|
|
|
|
#define HOSTREGS HOST( regs ) // 'regs' presumed
|
|
#define GUESTREGS GUEST( regs ) // 'regs' presumed
|
|
|
|
/* Instruction count for a CPU */
|
|
#define INSTCOUNT(_regs) \
|
|
(HOST(_regs)->prevcount + HOST(_regs)->instcount)
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Obtain/Release mainlock */
|
|
/*-------------------------------------------------------------------*/
|
|
/* mainlock is only obtained by a CPU thread. PROGRAMMING NOTE: */
|
|
/* The below #defines for OBTAIN_MAINLOCK and RELEASE_MAINLOCK */
|
|
/* MIGHT be overridden/nullified by machdep.h if atomic assists */
|
|
/* are available, since normally, that is the only reason for */
|
|
/* needing to obtain mainlock in the first place: because you */
|
|
/* need to do something atomically (e.g. need to do cmpxchg). */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#define OBTAIN_MAINLOCK_UNCONDITIONAL(_regs) \
|
|
do { \
|
|
if (HOST(_regs)->cpubit != (_regs)->sysblk->started_mask) { \
|
|
obtain_lock(&(_regs)->sysblk->mainlock); \
|
|
(_regs)->sysblk->mainowner = HOST(_regs)->cpuad; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define RELEASE_MAINLOCK_UNCONDITIONAL(_regs) \
|
|
do { \
|
|
if ((_regs)->sysblk->mainowner == HOST(_regs)->cpuad) { \
|
|
(_regs)->sysblk->mainowner = LOCK_OWNER_NONE; \
|
|
release_lock(&(_regs)->sysblk->mainlock); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define OBTAIN_MAINLOCK(_regs) OBTAIN_MAINLOCK_UNCONDITIONAL((_regs))
|
|
#define RELEASE_MAINLOCK(_regs) RELEASE_MAINLOCK_UNCONDITIONAL((_regs))
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Obtain/Release crwlock */
|
|
/* crwlock can be obtained by any thread */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#define OBTAIN_CRWLOCK() obtain_lock( &sysblk.crwlock )
|
|
#define RELEASE_CRWLOCK() release_lock( &sysblk.crwlock )
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Obtain/Release lock helper macros */
|
|
/* used mostly by channel.c */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#define OBTAIN_IOQLOCK() obtain_lock( &sysblk.ioqlock )
|
|
#define RELEASE_IOQLOCK() release_lock( &sysblk.ioqlock )
|
|
|
|
#define OBTAIN_IOINTQLK() obtain_lock( &sysblk.iointqlk )
|
|
#define RELEASE_IOINTQLK() release_lock( &sysblk.iointqlk )
|
|
|
|
#define OBTAIN_DEVLOCK( dev ) obtain_lock( &dev->lock )
|
|
#define RELEASE_DEVLOCK( dev ) release_lock( &dev->lock )
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Return whether specified CPU is waiting to acquire intlock or not */
|
|
/*-------------------------------------------------------------------*/
|
|
#define AT_SYNCPOINT(_regs) (HOST(_regs)->intwait)
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Macro to check if DEVBLK is for an existing device */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#if defined(_FEATURE_INTEGRATED_3270_CONSOLE)
|
|
#define IS_DEV(_dev) \
|
|
((_dev)->allocated && (((_dev)->pmcw.flag5 & PMCW5_V) || (_dev) == sysblk.sysgdev))
|
|
#else // !defined(_FEATURE_INTEGRATED_3270_CONSOLE)
|
|
#define IS_DEV(_dev) \
|
|
((_dev)->allocated && ((_dev)->pmcw.flag5 & PMCW5_V))
|
|
#endif // defined(_FEATURE_INTEGRATED_3270_CONSOLE)
|
|
|
|
#define INTEGRATED_CONS_FD INT_MAX
|
|
|
|
#define IS_INTEGRATED_CONS( _dev ) \
|
|
(1 \
|
|
&& !(_dev)->console \
|
|
&& (_dev)->connected \
|
|
&& (_dev)->fd == INTEGRATED_CONS_FD \
|
|
&& strlen( (_dev)->filename ) > 0 \
|
|
)
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* HDL macro to call optional function override */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#define HDC1(_func, _arg1) \
|
|
((_func) ? (_func) ((_arg1)) : (NULL))
|
|
#define HDC2(_func, _arg1,_arg2) \
|
|
((_func) ? (_func) ((_arg1),(_arg2)) : (NULL))
|
|
#define HDC3(_func, _arg1,_arg2,_arg3) \
|
|
((_func) ? (_func) ((_arg1),(_arg2),(_arg3)) : (NULL))
|
|
#define HDC4(_func, _arg1,_arg2,_arg3,_arg4) \
|
|
((_func) ? (_func) ((_arg1),(_arg2),(_arg3),(_arg4)) : (NULL))
|
|
#define HDC5(_func, _arg1,_arg2,_arg3,_arg4,_arg5) \
|
|
((_func) ? (_func) ((_arg1),(_arg2),(_arg3),(_arg4),(_arg5)) : (NULL))
|
|
#define HDC6(_func, _arg1,_arg2,_arg3,_arg4,_arg5,_arg6) \
|
|
((_func) ? (_func) ((_arg1),(_arg2),(_arg3),(_arg4),(_arg5),(_arg6)) : (NULL))
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Sleep for as long as we like (whole number of seconds) */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#define SLEEP(_n) \
|
|
do { \
|
|
unsigned int rc = (_n); \
|
|
while (rc) \
|
|
if ((rc = sleep (rc))) \
|
|
sched_yield(); \
|
|
} while (0)
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* CRASH (with hopefully a dump) */
|
|
/*-------------------------------------------------------------------*/
|
|
#define CRASH() do { volatile BYTE* p=NULL; *p=0; } while (0)
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Perform standard utility initialization */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#define INITIALIZE_UTILITY( def, desc, pgm ) \
|
|
argc = initialize_utility( argc, argv, def, desc, pgm )
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Assign name to thread (debugging aid) */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#if defined( _MSVC_ )
|
|
#define SET_THREAD_NAME_ID(t,n) \
|
|
do \
|
|
{ \
|
|
w32_set_thread_name((t),(n)); \
|
|
set_thread_name((t),(n)); \
|
|
} \
|
|
while (0)
|
|
#define SET_THREAD_NAME(n) SET_THREAD_NAME_ID(GetCurrentThreadId(),(n))
|
|
#elif defined( HAVE_PTHREAD_SETNAME_NP )
|
|
#define SET_THREAD_NAME_ID(t,n) \
|
|
do \
|
|
{ \
|
|
nix_set_thread_name((t),(n)); \
|
|
set_thread_name((t),(n)); \
|
|
} \
|
|
while (0)
|
|
#define SET_THREAD_NAME(n) SET_THREAD_NAME_ID(pthread_self(),(n))
|
|
#else
|
|
#define SET_THREAD_NAME_ID(t,n) \
|
|
do \
|
|
{ \
|
|
set_thread_name((t),(n)); \
|
|
} \
|
|
while (0)
|
|
#define SET_THREAD_NAME(n) SET_THREAD_NAME_ID(pthread_self(),(n))
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* ROOT privilege and capabilities macros */
|
|
/*-------------------------------------------------------------------*/
|
|
#if defined( NO_SETUID )
|
|
|
|
#define DROP_PRIVILEGES( _capa ) // (do nothing)
|
|
#define DROP_ALL_CAPS() // (do nothing)
|
|
#define SETMODE( _func ) // (do nothing)
|
|
|
|
#else // !defined( NO_SETUID )
|
|
|
|
#if defined( HAVE_SYS_CAPABILITY_H ) && defined( HAVE_SYS_PRCTL_H ) && defined( OPTION_CAPABILITIES )
|
|
|
|
#define DROP_PRIVILEGES(_capa) drop_privileges(_capa)
|
|
#define DROP_ALL_CAPS() drop_all_caps()
|
|
#define SETMODE(_x) // (do nothing)
|
|
|
|
#else // !defined( HAVE_SYS_CAPABILITY_H ) || !defined( HAVE_SYS_PRCTL_H ) || !defined( OPTION_CAPABILITIES )
|
|
|
|
/* SETMODE( INIT )
|
|
*
|
|
* Sets the saved uid to the effective uid, and sets the
|
|
* effective uid to the real uid, such that the program
|
|
* is running with normal user attributes, other than it
|
|
* may switch to the saved uid via SETMODE( ROOT ). This
|
|
* call is usually made upon entry to the setuid program.
|
|
*
|
|
* SETMODE( ROOT )
|
|
*
|
|
* Sets the saved uid to the real uid, and sets the real and
|
|
* effective uid to the saved uid. A setuid root program will
|
|
* enter 'root mode' and will have all the appropriate access.
|
|
*
|
|
* SETMODE( USER )
|
|
*
|
|
* Sets the real and effective uid to the uid of the caller.
|
|
* The saved uid will be the effective uid that was active
|
|
* upon entry to the program (before SETMODE( INIT )).
|
|
*
|
|
* SETMODE( TERM )
|
|
*
|
|
* Sets real, effective and saved uid to the real uid upon
|
|
* entry to the program. This call will revoke any setuid
|
|
* access that the thread/process has. It is important to
|
|
* issue this call BEFORE an exec to a shell or other program
|
|
* that could introduce integrity exposures when running with
|
|
* root access.
|
|
*/
|
|
|
|
#define DROP_PRIVILEGES(_capa) // (do nothing)
|
|
#define DROP_ALL_CAPS() // (do nothing)
|
|
#define SETMODE(_func) _SETMODE_ ## _func
|
|
|
|
#if defined( HAVE_SETRESUID )
|
|
|
|
#define _SETMODE_INIT \
|
|
\
|
|
do \
|
|
{ \
|
|
VERIFY( getresuid( &sysblk.ruid, &sysblk.euid, &sysblk.suid ) == 0 ); \
|
|
VERIFY( getresgid( &sysblk.rgid, &sysblk.egid, &sysblk.sgid ) == 0 ); \
|
|
VERIFY( setresgid( sysblk.rgid, sysblk.rgid, sysblk.egid ) == 0 ); \
|
|
VERIFY( setresuid( sysblk.ruid, sysblk.ruid, sysblk.euid ) == 0 ); \
|
|
} \
|
|
while(0)
|
|
|
|
|
|
#define _SETMODE_ROOT \
|
|
\
|
|
do \
|
|
{ \
|
|
VERIFY(!setresuid(sysblk.suid,sysblk.suid,sysblk.ruid)); \
|
|
} \
|
|
while(0)
|
|
|
|
|
|
#define _SETMODE_USER \
|
|
\
|
|
do \
|
|
{ \
|
|
VERIFY( setresuid( sysblk.ruid, sysblk.ruid, sysblk.suid ) == 0 ); \
|
|
} \
|
|
while(0)
|
|
|
|
|
|
#define _SETMODE_TERM \
|
|
\
|
|
do \
|
|
{ \
|
|
VERIFY( setresgid( sysblk.rgid, sysblk.rgid, sysblk.rgid ) == 0 ); \
|
|
VERIFY( setresuid( sysblk.ruid, sysblk.ruid, sysblk.ruid ) == 0 ); \
|
|
} \
|
|
while(0)
|
|
|
|
#elif defined( HAVE_SETREUID )
|
|
|
|
#define _SETMODE_INIT \
|
|
\
|
|
do \
|
|
{ \
|
|
sysblk.ruid = getuid(); \
|
|
sysblk.euid = geteuid(); \
|
|
sysblk.rgid = getgid(); \
|
|
sysblk.egid = getegid(); \
|
|
\
|
|
VERIFY( setregid( sysblk.egid, sysblk.rgid ) == 0 ); \
|
|
VERIFY( setreuid( sysblk.euid, sysblk.ruid ) == 0 ); \
|
|
} \
|
|
while(0)
|
|
|
|
|
|
#define _SETMODE_ROOT \
|
|
\
|
|
do \
|
|
{ \
|
|
VERIFY( setregid( sysblk.rgid, sysblk.egid ) == 0 ); \
|
|
VERIFY( setreuid( sysblk.ruid, sysblk.euid ) == 0 ); \
|
|
} \
|
|
while(0)
|
|
|
|
|
|
#define _SETMODE_USER \
|
|
\
|
|
do \
|
|
{ \
|
|
VERIFY( setregid( sysblk.egid, sysblk.rgid ) == 0 ); \
|
|
VERIFY( setreuid( sysblk.euid, sysblk.ruid ) == 0 ); \
|
|
} \
|
|
while(0)
|
|
|
|
|
|
#define _SETMODE_TERM \
|
|
\
|
|
do \
|
|
{ \
|
|
VERIFY( setgid( sysblk.rgid ) == 0 ); \
|
|
VERIFY( setuid( sysblk.ruid ) == 0 ); \
|
|
} \
|
|
while(0)
|
|
|
|
#else // !defined( HAVE_SETRESUID ) && !defined( HAVE_SETEREUID )
|
|
|
|
#error Cannot figure out how to swap effective UID/GID! Maybe you should #define NO_SETUID?
|
|
|
|
#endif // defined( HAVE_SETREUID ) || defined( HAVE_SETRESUID )
|
|
|
|
#endif // defined( HAVE_SYS_CAPABILITY_H ) && defined( HAVE_SYS_PRCTL_H ) && defined( OPTION_CAPABILITIES )
|
|
|
|
#endif // defined( NO_SETUID )
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Pipe signaling (thread signaling via pipe) */
|
|
/*-------------------------------------------------------------------*/
|
|
|
|
#define RECV_PIPE_SIGNAL( rfd, lock, flag ) \
|
|
\
|
|
do \
|
|
{ \
|
|
int f, saved_errno; BYTE c=0; \
|
|
\
|
|
saved_errno = get_HSO_errno(); \
|
|
{ \
|
|
obtain_lock( &(lock) ); \
|
|
{ \
|
|
if ((f = (flag)) >= 1) \
|
|
(flag) = 0; \
|
|
} \
|
|
release_lock( &(lock) ); \
|
|
\
|
|
if (f >= 1) \
|
|
VERIFY( read_pipe( (rfd), &c, 1 ) == 1); \
|
|
} \
|
|
set_HSO_errno( saved_errno ); \
|
|
} \
|
|
while(0)
|
|
|
|
|
|
#define SEND_PIPE_SIGNAL( wfd, lock, flag ) \
|
|
\
|
|
do \
|
|
{ \
|
|
int f, saved_errno; BYTE c=0; \
|
|
\
|
|
saved_errno = get_HSO_errno(); \
|
|
{ \
|
|
obtain_lock( &(lock) ); \
|
|
{ \
|
|
if ((f = (flag)) <= 0) \
|
|
(flag) = 1; \
|
|
} \
|
|
release_lock( &(lock) ); \
|
|
\
|
|
if (f <= 0) \
|
|
VERIFY( write_pipe( (wfd), &c, 1 ) == 1); \
|
|
} \
|
|
set_HSO_errno( saved_errno ); \
|
|
} \
|
|
while(0)
|
|
|
|
|
|
#define SUPPORT_WAKEUP_SELECT_VIA_PIPE( pipe_rfd, maxfd, prset ) \
|
|
\
|
|
do \
|
|
{ \
|
|
FD_SET( (pipe_rfd), (prset) ); \
|
|
\
|
|
(maxfd) = (maxfd) > (pipe_rfd) ? (maxfd) \
|
|
: (pipe_rfd); \
|
|
} \
|
|
while(0)
|
|
|
|
|
|
#define SUPPORT_WAKEUP_CONSOLE_SELECT_VIA_PIPE( maxfd, prset ) SUPPORT_WAKEUP_SELECT_VIA_PIPE( sysblk.cnslrpipe, (maxfd), (prset) )
|
|
#define SUPPORT_WAKEUP_SOCKDEV_SELECT_VIA_PIPE( maxfd, prset ) SUPPORT_WAKEUP_SELECT_VIA_PIPE( sysblk.sockrpipe, (maxfd), (prset) )
|
|
|
|
#define RECV_CONSOLE_THREAD_PIPE_SIGNAL() RECV_PIPE_SIGNAL( sysblk.cnslrpipe, sysblk.cnslpipe_lock, sysblk.cnslpipe_flag )
|
|
#define RECV_SOCKDEV_THREAD_PIPE_SIGNAL() RECV_PIPE_SIGNAL( sysblk.sockrpipe, sysblk.sockpipe_lock, sysblk.sockpipe_flag )
|
|
#define SIGNAL_CONSOLE_THREAD() SEND_PIPE_SIGNAL( sysblk.cnslwpipe, sysblk.cnslpipe_lock, sysblk.cnslpipe_flag )
|
|
#define SIGNAL_SOCKDEV_THREAD() SEND_PIPE_SIGNAL( sysblk.sockwpipe, sysblk.sockpipe_lock, sysblk.sockpipe_flag )
|
|
|
|
/*********************************************************************/
|
|
/* Define compiler error bypasses */
|
|
/*********************************************************************/
|
|
|
|
#if defined( _MSVC_ ) && !defined( __clang__ )
|
|
|
|
/*
|
|
* MS VC Bug ID 363375 Bypass
|
|
* Note: This error, or similar, also occurs w/VS2010 and VS2012.
|
|
* TODO: Verify if fixed in VS2013 or later.
|
|
*/
|
|
|
|
#define ENABLE_VS_BUG_ID_363375_BYPASS \
|
|
\
|
|
__pragma( optimize( "", off )) \
|
|
__pragma( optimize( "t", on ))
|
|
|
|
|
|
#define DISABLE_VS_BUG_ID_363375_BYPASS \
|
|
\
|
|
__pragma( optimize( "", on ))
|
|
|
|
#else // Linux
|
|
|
|
#define ENABLE_VS_BUG_ID_363375_BYPASS /* (nothing) */
|
|
#define DISABLE_VS_BUG_ID_363375_BYPASS /* (nothing) */
|
|
|
|
#endif // _MSVC_
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* CCW tracing helper macro */
|
|
/*-------------------------------------------------------------------*/
|
|
#define DISPLAY_CCW( _did, _dev, _ccw, _addr, _count, _flags ) \
|
|
\
|
|
display_ccw( (_did), (_dev), (_ccw), (_addr), (_count), (_flags), \
|
|
__FILE__, __LINE__, __FUNCTION__ )
|
|
|
|
|
|
/*-------------------------------------------------------------------*/
|
|
/* Hercules --> HercGUI / HercGUI <-- Hercules stream debugging */
|
|
/*-------------------------------------------------------------------*/
|
|
#ifdef HG_GH_DEBUG
|
|
|
|
#define OPEN_X_TO_X() /* Open both debugging files */ \
|
|
\
|
|
do \
|
|
{ \
|
|
if (!H_to_G) { \
|
|
H_to_G = fopen( \
|
|
H_to_G_PATH, "wb" ); \
|
|
setvbuf( H_to_G, NULL, _IONBF, 0 ); \
|
|
LOG_H_to_G( "opened...\n" ); \
|
|
} \
|
|
if (!H_fr_G) { \
|
|
H_fr_G = fopen( \
|
|
H_fr_G_PATH, "wb" ); \
|
|
setvbuf( H_fr_G, NULL, _IONBF, 0 ); \
|
|
LOG_H_fr_G( "opened...\n" ); \
|
|
} \
|
|
} \
|
|
while (0)
|
|
|
|
|
|
#define CLOSE_X_TO_X() /* Close both debugging files */ \
|
|
\
|
|
do \
|
|
{ \
|
|
if (H_to_G) { \
|
|
LOG_H_to_G( "closed...\n" ); \
|
|
fclose( H_to_G ); \
|
|
H_to_G = NULL; \
|
|
} \
|
|
if (G_fr_H) { \
|
|
LOG_G_fr_H( "closed...\n" ); \
|
|
fclose( G_fr_H ); \
|
|
G_fr_H = NULL; \
|
|
} \
|
|
} \
|
|
while (0)
|
|
|
|
|
|
#define LOG_X_to_X( file, msg ) /* log a stream debugging message */ \
|
|
\
|
|
do \
|
|
{ \
|
|
size_t size = strlen( msg ); \
|
|
fwrite( msg, size, 1, file ); \
|
|
fflush( file ); \
|
|
} \
|
|
while (0)
|
|
|
|
|
|
#define LOG_X_fr_X( file, msg ) /* log a stream debugging message */ \
|
|
\
|
|
do \
|
|
{ \
|
|
fprintf( file, "%s\n", msg ); \
|
|
fflush( file ); \
|
|
} \
|
|
while (0)
|
|
|
|
|
|
#define LOG_H_to_G( msg ) LOG_X_to_X( H_to_G, msg )
|
|
#define LOG_H_fr_G( msg ) LOG_X_fr_X( H_fr_G, msg )
|
|
|
|
#else
|
|
|
|
#define OPEN_X_TO_X() /* (nothing) */
|
|
#define CLOSE_X_TO_X() /* (nothing) */
|
|
|
|
#define LOG_H_to_G( msg ) /* (nothing) */
|
|
#define LOG_H_fr_G( msg ) /* (nothing) */
|
|
|
|
#endif // HG_GH_DEBUG
|
|
|
|
#endif // _HMACROS_H
|